Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/s390x/lower/isle.rs
3090 views
1
//! ISLE integration glue code for s390x lowering.
2
3
// Pull in the ISLE generated code.
4
pub mod generated_code;
5
6
// Types that the generated ISLE code uses via `use super::*`.
7
use crate::ir::ExternalName;
8
use crate::isa::s390x::S390xBackend;
9
use crate::isa::s390x::abi::REG_SAVE_AREA_SIZE;
10
use 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
};
15
use crate::machinst::isle::*;
16
use crate::machinst::{CallInfo, MachLabel, Reg, TryCallInfo, non_writable_value_regs};
17
use crate::{
18
ir::{
19
AtomicRmwOp, BlockCall, Endianness, Inst, InstructionData, KnownSymbol, MemFlags, Opcode,
20
TrapCode, Value, ValueList, condcodes::*, immediates::*, types::*,
21
},
22
isa::CallConv,
23
machinst::{
24
ArgPair, CallArgList, CallRetList, InstOutput, MachInst, VCodeConstant, VCodeConstantData,
25
},
26
};
27
use alloc::boxed::Box;
28
use alloc::vec::Vec;
29
use core::cell::Cell;
30
use regalloc2::PReg;
31
32
type BoxCallInfo = Box<CallInfo<CallInstDest>>;
33
type BoxReturnCallInfo = Box<ReturnCallInfo<CallInstDest>>;
34
type VecMachLabel = Vec<MachLabel>;
35
type BoxExternalName = Box<ExternalName>;
36
type BoxSymbolReloc = Box<SymbolReloc>;
37
type VecMInst = Vec<MInst>;
38
type VecMInstBuilder = Cell<Vec<MInst>>;
39
type VecArgPair = Vec<ArgPair>;
40
41
/// The main entry point for lowering with ISLE.
42
pub(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.
54
pub(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
66
impl 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(), MemFlags::trusted());
91
let dst_mem = MemArg::reg(stack_reg(), MemFlags::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 defered 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 mie3_enabled(&mut self, _: Type) -> Option<()> {
217
if self.backend.isa_flags.has_mie3() {
218
Some(())
219
} else {
220
None
221
}
222
}
223
224
#[inline]
225
fn mie3_disabled(&mut self, _: Type) -> Option<()> {
226
if !self.backend.isa_flags.has_mie3() {
227
Some(())
228
} else {
229
None
230
}
231
}
232
233
#[inline]
234
fn mie4_enabled(&mut self, _: Type) -> Option<()> {
235
if self.backend.isa_flags.has_mie4() {
236
Some(())
237
} else {
238
None
239
}
240
}
241
242
#[inline]
243
fn mie4_disabled(&mut self, _: Type) -> Option<()> {
244
if !self.backend.isa_flags.has_mie4() {
245
Some(())
246
} else {
247
None
248
}
249
}
250
251
#[inline]
252
fn vxrs_ext2_enabled(&mut self, _: Type) -> Option<()> {
253
if self.backend.isa_flags.has_vxrs_ext2() {
254
Some(())
255
} else {
256
None
257
}
258
}
259
260
#[inline]
261
fn vxrs_ext2_disabled(&mut self, _: Type) -> Option<()> {
262
if !self.backend.isa_flags.has_vxrs_ext2() {
263
Some(())
264
} else {
265
None
266
}
267
}
268
269
#[inline]
270
fn vxrs_ext3_enabled(&mut self, _: Type) -> Option<()> {
271
if self.backend.isa_flags.has_vxrs_ext3() {
272
Some(())
273
} else {
274
None
275
}
276
}
277
278
#[inline]
279
fn vxrs_ext3_disabled(&mut self, _: Type) -> Option<()> {
280
if !self.backend.isa_flags.has_vxrs_ext3() {
281
Some(())
282
} else {
283
None
284
}
285
}
286
287
#[inline]
288
fn writable_gpr(&mut self, regno: u8) -> WritableReg {
289
writable_gpr(regno)
290
}
291
292
#[inline]
293
fn zero_reg(&mut self) -> Reg {
294
zero_reg()
295
}
296
297
#[inline]
298
fn gpr32_ty(&mut self, ty: Type) -> Option<Type> {
299
match ty {
300
I8 | I16 | I32 => Some(ty),
301
_ => None,
302
}
303
}
304
305
#[inline]
306
fn gpr64_ty(&mut self, ty: Type) -> Option<Type> {
307
match ty {
308
I64 => Some(ty),
309
_ => None,
310
}
311
}
312
313
#[inline]
314
fn vr128_ty(&mut self, ty: Type) -> Option<Type> {
315
match ty {
316
I128 | F128 => Some(ty),
317
_ if ty.is_vector() && ty.bits() == 128 => Some(ty),
318
_ => None,
319
}
320
}
321
322
#[inline]
323
fn uimm32shifted(&mut self, n: u32, shift: u8) -> UImm32Shifted {
324
UImm32Shifted::maybe_with_shift(n, shift).unwrap()
325
}
326
327
#[inline]
328
fn uimm16shifted(&mut self, n: u16, shift: u8) -> UImm16Shifted {
329
UImm16Shifted::maybe_with_shift(n, shift).unwrap()
330
}
331
332
#[inline]
333
fn i64_nonequal(&mut self, val: i64, cmp: i64) -> Option<i64> {
334
if val != cmp { Some(val) } else { None }
335
}
336
337
#[inline]
338
fn u64_pair_split(&mut self, n: u128) -> (u64, u64) {
339
((n >> 64) as u64, n as u64)
340
}
341
342
#[inline]
343
fn u64_pair_concat(&mut self, hi: u64, lo: u64) -> u128 {
344
(hi as u128) << 64 | (lo as u128)
345
}
346
347
#[inline]
348
fn u32_pair_split(&mut self, n: u64) -> (u32, u32) {
349
((n >> 32) as u32, n as u32)
350
}
351
352
#[inline]
353
fn u32_pair_concat(&mut self, hi: u32, lo: u32) -> u64 {
354
(hi as u64) << 32 | (lo as u64)
355
}
356
357
#[inline]
358
fn u16_pair_split(&mut self, n: u32) -> (u16, u16) {
359
((n >> 16) as u16, n as u16)
360
}
361
362
#[inline]
363
fn u16_pair_concat(&mut self, hi: u16, lo: u16) -> u32 {
364
(hi as u32) << 16 | (lo as u32)
365
}
366
367
#[inline]
368
fn u8_pair_split(&mut self, n: u16) -> (u8, u8) {
369
((n >> 8) as u8, n as u8)
370
}
371
372
#[inline]
373
fn u8_pair_concat(&mut self, hi: u8, lo: u8) -> u16 {
374
(hi as u16) << 8 | (lo as u16)
375
}
376
377
#[inline]
378
fn u64_nonzero_hipart(&mut self, n: u64) -> Option<u64> {
379
let part = n & 0xffff_ffff_0000_0000;
380
if part != 0 { Some(part) } else { None }
381
}
382
383
#[inline]
384
fn u64_nonzero_lopart(&mut self, n: u64) -> Option<u64> {
385
let part = n & 0x0000_0000_ffff_ffff;
386
if part != 0 { Some(part) } else { None }
387
}
388
389
#[inline]
390
fn uimm32shifted_from_u64(&mut self, n: u64) -> Option<UImm32Shifted> {
391
UImm32Shifted::maybe_from_u64(n)
392
}
393
394
#[inline]
395
fn uimm16shifted_from_u64(&mut self, n: u64) -> Option<UImm16Shifted> {
396
UImm16Shifted::maybe_from_u64(n)
397
}
398
399
#[inline]
400
fn lane_order(&mut self) -> LaneOrder {
401
LaneOrder::from(self.lower_ctx.abi().call_conv())
402
}
403
404
#[inline]
405
fn be_lane_idx(&mut self, ty: Type, idx: u8) -> u8 {
406
match self.lane_order() {
407
LaneOrder::LittleEndian => ty.lane_count() as u8 - 1 - idx,
408
LaneOrder::BigEndian => idx,
409
}
410
}
411
412
#[inline]
413
fn be_vec_const(&mut self, ty: Type, n: u128) -> u128 {
414
match self.lane_order() {
415
LaneOrder::LittleEndian => n,
416
LaneOrder::BigEndian if ty.lane_count() == 1 => n,
417
LaneOrder::BigEndian => {
418
let lane_count = ty.lane_count();
419
let lane_bits = ty.lane_bits();
420
let lane_mask = (1u128 << lane_bits) - 1;
421
let mut n_le = n;
422
let mut n_be = 0u128;
423
for _ in 0..lane_count {
424
n_be = (n_be << lane_bits) | (n_le & lane_mask);
425
n_le = n_le >> lane_bits;
426
}
427
n_be
428
}
429
}
430
}
431
432
#[inline]
433
fn lane_byte_mask(&mut self, ty: Type, idx: u8) -> u16 {
434
let lane_bytes = (ty.lane_bits() / 8) as u8;
435
let lane_mask = (1u16 << lane_bytes) - 1;
436
lane_mask << (16 - ((idx + 1) * lane_bytes))
437
}
438
439
#[inline]
440
fn shuffle_mask_from_u128(&mut self, idx: u128) -> (u128, u16) {
441
let bytes = match self.lane_order() {
442
LaneOrder::LittleEndian => idx.to_be_bytes().map(|x| {
443
if x < 16 {
444
15 - x
445
} else if x < 32 {
446
47 - x
447
} else {
448
128
449
}
450
}),
451
LaneOrder::BigEndian => idx.to_le_bytes().map(|x| if x < 32 { x } else { 128 }),
452
};
453
let and_mask = bytes.iter().fold(0, |acc, &x| (acc << 1) | (x < 32) as u16);
454
let permute_mask = u128::from_be_bytes(bytes);
455
(permute_mask, and_mask)
456
}
457
458
#[inline]
459
fn u64_from_value(&mut self, val: Value) -> Option<u64> {
460
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
461
let constant = self.lower_ctx.get_constant(inst)?;
462
let ty = self.lower_ctx.output_ty(inst, 0);
463
Some(zero_extend_to_u64(constant, self.ty_bits(ty)))
464
}
465
466
#[inline]
467
fn u64_from_inverted_value(&mut self, val: Value) -> Option<u64> {
468
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
469
let constant = self.lower_ctx.get_constant(inst)?;
470
let ty = self.lower_ctx.output_ty(inst, 0);
471
Some(zero_extend_to_u64(!constant, self.ty_bits(ty)))
472
}
473
474
#[inline]
475
fn u32_from_value(&mut self, val: Value) -> Option<u32> {
476
let constant = self.u64_from_value(val)?;
477
let imm = u32::try_from(constant).ok()?;
478
Some(imm)
479
}
480
481
#[inline]
482
fn u8_from_value(&mut self, val: Value) -> Option<u8> {
483
let constant = self.u64_from_value(val)?;
484
let imm = u8::try_from(constant).ok()?;
485
Some(imm)
486
}
487
488
#[inline]
489
fn u64_from_signed_value(&mut self, val: Value) -> Option<u64> {
490
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
491
let constant = self.lower_ctx.get_constant(inst)?;
492
let ty = self.lower_ctx.output_ty(inst, 0);
493
Some(sign_extend_to_u64(constant, self.ty_bits(ty)))
494
}
495
496
#[inline]
497
fn i64_from_value(&mut self, val: Value) -> Option<i64> {
498
let constant = self.u64_from_signed_value(val)? as i64;
499
Some(constant)
500
}
501
502
#[inline]
503
fn i32_from_value(&mut self, val: Value) -> Option<i32> {
504
let constant = self.u64_from_signed_value(val)? as i64;
505
let imm = i32::try_from(constant).ok()?;
506
Some(imm)
507
}
508
509
#[inline]
510
fn i16_from_value(&mut self, val: Value) -> Option<i16> {
511
let constant = self.u64_from_signed_value(val)? as i64;
512
let imm = i16::try_from(constant).ok()?;
513
Some(imm)
514
}
515
516
#[inline]
517
fn i16_from_swapped_value(&mut self, val: Value) -> Option<i16> {
518
let constant = self.u64_from_signed_value(val)? as i64;
519
let imm = i16::try_from(constant).ok()?;
520
Some(imm.swap_bytes())
521
}
522
523
#[inline]
524
fn i64_from_negated_value(&mut self, val: Value) -> Option<i64> {
525
let constant = self.u64_from_signed_value(val)? as i64;
526
let imm = constant.wrapping_neg();
527
Some(imm)
528
}
529
530
#[inline]
531
fn i32_from_negated_value(&mut self, val: Value) -> Option<i32> {
532
let constant = self.u64_from_signed_value(val)? as i64;
533
let imm = i32::try_from(constant.wrapping_neg()).ok()?;
534
Some(imm)
535
}
536
537
#[inline]
538
fn i16_from_negated_value(&mut self, val: Value) -> Option<i16> {
539
let constant = self.u64_from_signed_value(val)? as i64;
540
let imm = i16::try_from(constant.wrapping_neg()).ok()?;
541
Some(imm)
542
}
543
544
#[inline]
545
fn uimm16shifted_from_value(&mut self, val: Value) -> Option<UImm16Shifted> {
546
let constant = self.u64_from_value(val)?;
547
UImm16Shifted::maybe_from_u64(constant)
548
}
549
550
#[inline]
551
fn uimm32shifted_from_value(&mut self, val: Value) -> Option<UImm32Shifted> {
552
let constant = self.u64_from_value(val)?;
553
UImm32Shifted::maybe_from_u64(constant)
554
}
555
556
#[inline]
557
fn uimm16shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm16Shifted> {
558
let constant = self.u64_from_inverted_value(val)?;
559
let imm = UImm16Shifted::maybe_from_u64(constant)?;
560
Some(imm.negate_bits())
561
}
562
563
#[inline]
564
fn uimm32shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm32Shifted> {
565
let constant = self.u64_from_inverted_value(val)?;
566
let imm = UImm32Shifted::maybe_from_u64(constant)?;
567
Some(imm.negate_bits())
568
}
569
570
#[inline]
571
fn len_minus_one(&mut self, len: u64) -> Option<u8> {
572
if len > 0 && len <= 256 {
573
Some((len - 1) as u8)
574
} else {
575
None
576
}
577
}
578
579
#[inline]
580
fn mask_amt_imm(&mut self, ty: Type, amt: i64) -> u8 {
581
let mask = ty.lane_bits() - 1;
582
(amt as u8) & (mask as u8)
583
}
584
585
#[inline]
586
fn mask_as_cond(&mut self, mask: u8) -> Cond {
587
Cond::from_mask(mask)
588
}
589
590
#[inline]
591
fn intcc_as_cond(&mut self, cc: &IntCC) -> Cond {
592
Cond::from_intcc(*cc)
593
}
594
595
#[inline]
596
fn floatcc_as_cond(&mut self, cc: &FloatCC) -> Cond {
597
Cond::from_floatcc(*cc)
598
}
599
600
#[inline]
601
fn invert_cond(&mut self, cond: &Cond) -> Cond {
602
Cond::invert(*cond)
603
}
604
605
#[inline]
606
fn signed(&mut self, cc: &IntCC) -> Option<()> {
607
if condcode_is_signed(*cc) {
608
Some(())
609
} else {
610
None
611
}
612
}
613
614
#[inline]
615
fn unsigned(&mut self, cc: &IntCC) -> Option<()> {
616
if !condcode_is_signed(*cc) {
617
Some(())
618
} else {
619
None
620
}
621
}
622
623
#[inline]
624
fn zero_offset(&mut self) -> Offset32 {
625
Offset32::new(0)
626
}
627
628
#[inline]
629
fn i64_from_offset(&mut self, off: Offset32) -> i64 {
630
i64::from(off)
631
}
632
633
#[inline]
634
fn fcvt_to_uint_ub32(&mut self, size: u8) -> u64 {
635
(2.0_f32).powi(size.into()).to_bits() as u64
636
}
637
638
#[inline]
639
fn fcvt_to_uint_lb32(&mut self) -> u64 {
640
(-1.0_f32).to_bits() as u64
641
}
642
643
#[inline]
644
fn fcvt_to_uint_ub64(&mut self, size: u8) -> u64 {
645
(2.0_f64).powi(size.into()).to_bits()
646
}
647
648
#[inline]
649
fn fcvt_to_uint_lb64(&mut self) -> u64 {
650
(-1.0_f64).to_bits()
651
}
652
653
#[inline]
654
fn fcvt_to_uint_ub128(&mut self, size: u8) -> u128 {
655
Ieee128::pow2(size).bits()
656
}
657
658
#[inline]
659
fn fcvt_to_uint_lb128(&mut self) -> u128 {
660
(-Ieee128::pow2(0)).bits()
661
}
662
663
#[inline]
664
fn fcvt_to_sint_ub32(&mut self, size: u8) -> u64 {
665
(2.0_f32).powi((size - 1).into()).to_bits() as u64
666
}
667
668
#[inline]
669
fn fcvt_to_sint_lb32(&mut self, size: u8) -> u64 {
670
let lb = (-2.0_f32).powi((size - 1).into());
671
core::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits()) as u64
672
}
673
674
#[inline]
675
fn fcvt_to_sint_ub64(&mut self, size: u8) -> u64 {
676
(2.0_f64).powi((size - 1).into()).to_bits()
677
}
678
679
#[inline]
680
fn fcvt_to_sint_lb64(&mut self, size: u8) -> u64 {
681
let lb = (-2.0_f64).powi((size - 1).into());
682
core::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits())
683
}
684
685
#[inline]
686
fn fcvt_to_sint_ub128(&mut self, size: u8) -> u128 {
687
Ieee128::pow2(size - 1).bits()
688
}
689
690
#[inline]
691
fn fcvt_to_sint_lb128(&mut self, size: u8) -> u128 {
692
Ieee128::fcvt_to_sint_negative_overflow(size).bits()
693
}
694
695
#[inline]
696
fn littleendian(&mut self, flags: MemFlags) -> Option<()> {
697
let endianness = flags.endianness(Endianness::Big);
698
if endianness == Endianness::Little {
699
Some(())
700
} else {
701
None
702
}
703
}
704
705
#[inline]
706
fn bigendian(&mut self, flags: MemFlags) -> Option<()> {
707
let endianness = flags.endianness(Endianness::Big);
708
if endianness == Endianness::Big {
709
Some(())
710
} else {
711
None
712
}
713
}
714
715
#[inline]
716
fn memflags_trusted(&mut self) -> MemFlags {
717
MemFlags::trusted()
718
}
719
720
#[inline]
721
fn memarg_imm_from_offset(&mut self, imm: Offset32) -> Option<SImm20> {
722
SImm20::maybe_from_i64(i64::from(imm))
723
}
724
725
#[inline]
726
fn memarg_imm_from_offset_plus_bias(&mut self, imm: Offset32, bias: u8) -> Option<SImm20> {
727
let final_offset = i64::from(imm) + bias as i64;
728
SImm20::maybe_from_i64(final_offset)
729
}
730
731
#[inline]
732
fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, bias: u8, flags: MemFlags) -> MemArg {
733
MemArg::BXD12 {
734
base: x,
735
index: y,
736
disp: UImm12::maybe_from_u64(bias as u64).unwrap(),
737
flags,
738
}
739
}
740
741
#[inline]
742
fn memarg_reg_plus_reg_plus_off(
743
&mut self,
744
x: Reg,
745
y: Reg,
746
offset: &SImm20,
747
flags: MemFlags,
748
) -> MemArg {
749
if let Some(imm) = UImm12::maybe_from_simm20(*offset) {
750
MemArg::BXD12 {
751
base: x,
752
index: y,
753
disp: imm,
754
flags,
755
}
756
} else {
757
MemArg::BXD20 {
758
base: x,
759
index: y,
760
disp: *offset,
761
flags,
762
}
763
}
764
}
765
766
#[inline]
767
fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, bias: u8, flags: MemFlags) -> MemArg {
768
MemArg::reg_plus_off(reg, off + (bias as i64), flags)
769
}
770
771
#[inline]
772
fn memarg_symbol(&mut self, name: ExternalName, offset: i32, flags: MemFlags) -> MemArg {
773
MemArg::Symbol {
774
name: Box::new(name),
775
offset,
776
flags,
777
}
778
}
779
780
#[inline]
781
fn memarg_got(&mut self) -> MemArg {
782
MemArg::Symbol {
783
name: Box::new(ExternalName::KnownSymbol(KnownSymbol::ElfGlobalOffsetTable)),
784
offset: 0,
785
flags: MemFlags::trusted(),
786
}
787
}
788
789
#[inline]
790
fn memarg_const(&mut self, constant: VCodeConstant) -> MemArg {
791
MemArg::Constant { constant }
792
}
793
794
#[inline]
795
fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option<i32> {
796
let off = i32::try_from(off1 + off2).ok()?;
797
if off & 1 == 0 { Some(off) } else { None }
798
}
799
800
#[inline]
801
fn memarg_frame_pointer_offset(&mut self) -> MemArg {
802
// The frame pointer (back chain) is stored directly at SP.
803
MemArg::reg(stack_reg(), MemFlags::trusted())
804
}
805
806
#[inline]
807
fn memarg_return_address_offset(&mut self) -> MemArg {
808
// The return address is stored 14 pointer-sized slots above the initial SP.
809
MemArg::InitialSPOffset { off: 14 * 8 }
810
}
811
812
#[inline]
813
fn inst_builder_new(&mut self) -> VecMInstBuilder {
814
Cell::new(Vec::<MInst>::new())
815
}
816
817
#[inline]
818
fn inst_builder_push(&mut self, builder: &VecMInstBuilder, inst: &MInst) -> Unit {
819
let mut vec = builder.take();
820
vec.push(inst.clone());
821
builder.set(vec);
822
}
823
824
#[inline]
825
fn inst_builder_finish(&mut self, builder: &VecMInstBuilder) -> Vec<MInst> {
826
builder.take()
827
}
828
829
#[inline]
830
fn real_reg(&mut self, reg: WritableReg) -> Option<WritableReg> {
831
if reg.to_reg().is_real() {
832
Some(reg)
833
} else {
834
None
835
}
836
}
837
838
#[inline]
839
fn same_reg(&mut self, dst: WritableReg, src: Reg) -> Option<Reg> {
840
if dst.to_reg() == src { Some(src) } else { None }
841
}
842
843
#[inline]
844
fn sinkable_inst(&mut self, val: Value) -> Option<Inst> {
845
self.is_sinkable_inst(val)
846
}
847
848
#[inline]
849
fn emit(&mut self, inst: &MInst) -> Unit {
850
self.lower_ctx.emit(inst.clone());
851
}
852
853
#[inline]
854
fn preg_stack(&mut self) -> PReg {
855
stack_reg().to_real_reg().unwrap().into()
856
}
857
858
#[inline]
859
fn preg_gpr_0(&mut self) -> PReg {
860
gpr(0).to_real_reg().unwrap().into()
861
}
862
863
#[inline]
864
fn writable_regpair(&mut self, hi: WritableReg, lo: WritableReg) -> WritableRegPair {
865
WritableRegPair { hi, lo }
866
}
867
868
#[inline]
869
fn writable_regpair_hi(&mut self, w: WritableRegPair) -> WritableReg {
870
w.hi
871
}
872
873
#[inline]
874
fn writable_regpair_lo(&mut self, w: WritableRegPair) -> WritableReg {
875
w.lo
876
}
877
878
#[inline]
879
fn regpair(&mut self, hi: Reg, lo: Reg) -> RegPair {
880
RegPair { hi, lo }
881
}
882
883
#[inline]
884
fn regpair_hi(&mut self, w: RegPair) -> Reg {
885
w.hi
886
}
887
888
#[inline]
889
fn regpair_lo(&mut self, w: RegPair) -> Reg {
890
w.lo
891
}
892
}
893
894
/// Zero-extend the low `from_bits` bits of `value` to a full u64.
895
#[inline]
896
fn zero_extend_to_u64(value: u64, from_bits: u8) -> u64 {
897
assert!(from_bits <= 64);
898
if from_bits >= 64 {
899
value
900
} else {
901
value & ((1u64 << from_bits) - 1)
902
}
903
}
904
905
/// Sign-extend the low `from_bits` bits of `value` to a full u64.
906
#[inline]
907
fn sign_extend_to_u64(value: u64, from_bits: u8) -> u64 {
908
assert!(from_bits <= 64);
909
if from_bits >= 64 {
910
value
911
} else {
912
(((value << (64 - from_bits)) as i64) >> (64 - from_bits)) as u64
913
}
914
}
915
916
/// Determines whether this condcode interprets inputs as signed or
917
/// unsigned. See the documentation for the `icmp` instruction in
918
/// cranelift-codegen/meta/src/shared/instructions.rs for further insights
919
/// into this.
920
#[inline]
921
fn condcode_is_signed(cc: IntCC) -> bool {
922
match cc {
923
IntCC::Equal => false,
924
IntCC::NotEqual => false,
925
IntCC::SignedGreaterThanOrEqual => true,
926
IntCC::SignedGreaterThan => true,
927
IntCC::SignedLessThanOrEqual => true,
928
IntCC::SignedLessThan => true,
929
IntCC::UnsignedGreaterThanOrEqual => false,
930
IntCC::UnsignedGreaterThan => false,
931
IntCC::UnsignedLessThanOrEqual => false,
932
IntCC::UnsignedLessThan => false,
933
}
934
}
935
936