Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/s390x/inst/emit.rs
3101 views
1
//! S390x ISA: binary code emission.
2
3
use crate::ir::{self, LibCall, MemFlags, TrapCode};
4
use crate::isa::CallConv;
5
use crate::isa::s390x::abi::REG_SAVE_AREA_SIZE;
6
use crate::isa::s390x::inst::*;
7
use crate::isa::s390x::settings as s390x_settings;
8
use cranelift_control::ControlPlane;
9
10
/// Debug macro for testing that a regpair is valid: that the high register is even, and the low
11
/// register is one higher than the high register.
12
macro_rules! debug_assert_valid_regpair {
13
($hi:expr, $lo:expr) => {
14
if cfg!(debug_assertions) {
15
match ($hi.to_real_reg(), $lo.to_real_reg()) {
16
(Some(hi), Some(lo)) => {
17
assert!(
18
hi.hw_enc() % 2 == 0,
19
"High register is not even: {}",
20
show_reg($hi)
21
);
22
assert_eq!(
23
hi.hw_enc() + 1,
24
lo.hw_enc(),
25
"Low register is not valid: {}, {}",
26
show_reg($hi),
27
show_reg($lo)
28
);
29
}
30
31
_ => {
32
panic!(
33
"Expected real registers for {} {}",
34
show_reg($hi),
35
show_reg($lo)
36
);
37
}
38
}
39
}
40
};
41
}
42
43
macro_rules! debug_assert_valid_fp_regpair {
44
($hi:expr, $lo:expr) => {
45
if cfg!(debug_assertions) {
46
match ($hi.to_real_reg(), $lo.to_real_reg()) {
47
(Some(hi), Some(lo)) => {
48
assert!(
49
hi.hw_enc() & 2 == 0,
50
"High register is not valid: {}",
51
show_reg($hi)
52
);
53
assert_eq!(
54
hi.hw_enc() + 2,
55
lo.hw_enc(),
56
"Low register is not valid: {}, {}",
57
show_reg($hi),
58
show_reg($lo)
59
);
60
}
61
62
_ => {
63
panic!(
64
"Expected real registers for {} {}",
65
show_reg($hi),
66
show_reg($lo)
67
);
68
}
69
}
70
}
71
};
72
}
73
74
const OPCODE_BRAS: u16 = 0xa75;
75
const OPCODE_BCR: u16 = 0xa74;
76
const OPCODE_LDR: u16 = 0x28;
77
const OPCODE_VLR: u16 = 0xe756;
78
79
/// Type(s) of memory instructions available for mem_finalize.
80
pub struct MemInstType {
81
/// True if 12-bit unsigned displacement is supported.
82
pub have_d12: bool,
83
/// True if 20-bit signed displacement is supported.
84
pub have_d20: bool,
85
/// True if PC-relative addressing is supported (memory access).
86
pub have_pcrel: bool,
87
/// True if PC-relative addressing is supported (load address).
88
pub have_unaligned_pcrel: bool,
89
/// True if an index register is supported.
90
pub have_index: bool,
91
}
92
93
/// Memory addressing mode finalization: convert "special" modes (e.g.,
94
/// generic arbitrary stack offset) into real addressing modes, possibly by
95
/// emitting some helper instructions that come immediately before the use
96
/// of this amode.
97
pub fn mem_finalize(
98
mem: &MemArg,
99
state: &EmitState,
100
mi: MemInstType,
101
) -> (SmallVec<[Inst; 4]>, MemArg) {
102
let mut insts = SmallVec::new();
103
104
// Resolve virtual addressing modes.
105
let mem = match mem {
106
&MemArg::RegOffset { off, .. }
107
| &MemArg::InitialSPOffset { off }
108
| &MemArg::IncomingArgOffset { off }
109
| &MemArg::OutgoingArgOffset { off }
110
| &MemArg::SlotOffset { off }
111
| &MemArg::SpillOffset { off } => {
112
let base = match mem {
113
&MemArg::RegOffset { reg, .. } => reg,
114
&MemArg::InitialSPOffset { .. }
115
| &MemArg::IncomingArgOffset { .. }
116
| &MemArg::OutgoingArgOffset { .. }
117
| &MemArg::SlotOffset { .. }
118
| &MemArg::SpillOffset { .. } => stack_reg(),
119
_ => unreachable!(),
120
};
121
let adj = match mem {
122
&MemArg::IncomingArgOffset { .. } => i64::from(
123
state.incoming_args_size
124
+ REG_SAVE_AREA_SIZE
125
+ state.frame_layout().clobber_size
126
+ state.frame_layout().fixed_frame_storage_size
127
+ state.frame_layout().outgoing_args_size
128
+ state.nominal_sp_offset,
129
),
130
&MemArg::InitialSPOffset { .. } => i64::from(
131
state.frame_layout().clobber_size
132
+ state.frame_layout().fixed_frame_storage_size
133
+ state.frame_layout().outgoing_args_size
134
+ state.nominal_sp_offset,
135
),
136
&MemArg::SpillOffset { .. } => i64::from(
137
state.frame_layout().stackslots_size
138
+ state.frame_layout().outgoing_args_size
139
+ state.nominal_sp_offset,
140
),
141
&MemArg::SlotOffset { .. } => {
142
i64::from(state.frame_layout().outgoing_args_size + state.nominal_sp_offset)
143
}
144
&MemArg::OutgoingArgOffset { .. } => {
145
i64::from(REG_SAVE_AREA_SIZE) - i64::from(state.outgoing_sp_offset)
146
}
147
_ => 0,
148
};
149
let off = off + adj;
150
151
if let Some(disp) = UImm12::maybe_from_u64(off as u64) {
152
MemArg::BXD12 {
153
base,
154
index: zero_reg(),
155
disp,
156
flags: mem.get_flags(),
157
}
158
} else if let Some(disp) = SImm20::maybe_from_i64(off) {
159
MemArg::BXD20 {
160
base,
161
index: zero_reg(),
162
disp,
163
flags: mem.get_flags(),
164
}
165
} else {
166
let tmp = writable_spilltmp_reg();
167
assert!(base != tmp.to_reg());
168
if let Ok(imm) = i16::try_from(off) {
169
insts.push(Inst::Mov64SImm16 { rd: tmp, imm });
170
} else if let Ok(imm) = i32::try_from(off) {
171
insts.push(Inst::Mov64SImm32 { rd: tmp, imm });
172
} else {
173
// The offset must be smaller than the stack frame size,
174
// which the ABI code limits to 128 MB.
175
unreachable!();
176
}
177
MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags())
178
}
179
}
180
_ => mem.clone(),
181
};
182
183
// If this addressing mode cannot be handled by the instruction, use load-address.
184
let need_load_address = match &mem {
185
&MemArg::Label { .. } | &MemArg::Constant { .. } if !mi.have_pcrel => true,
186
&MemArg::Symbol { .. } if !mi.have_pcrel => true,
187
&MemArg::Symbol { flags, .. } if !mi.have_unaligned_pcrel && !flags.aligned() => true,
188
&MemArg::BXD20 { .. } if !mi.have_d20 => true,
189
&MemArg::BXD12 { index, .. } | &MemArg::BXD20 { index, .. } if !mi.have_index => {
190
index != zero_reg()
191
}
192
_ => false,
193
};
194
let mem = if need_load_address {
195
let flags = mem.get_flags();
196
let tmp = writable_spilltmp_reg();
197
insts.push(Inst::LoadAddr { rd: tmp, mem });
198
MemArg::reg(tmp.to_reg(), flags)
199
} else {
200
mem
201
};
202
203
// Convert 12-bit displacement to 20-bit if required.
204
let mem = match &mem {
205
&MemArg::BXD12 {
206
base,
207
index,
208
disp,
209
flags,
210
} if !mi.have_d12 => {
211
assert!(mi.have_d20);
212
MemArg::BXD20 {
213
base,
214
index,
215
disp: SImm20::from_uimm12(disp),
216
flags,
217
}
218
}
219
_ => mem,
220
};
221
222
(insts, mem)
223
}
224
225
pub fn mem_emit(
226
rd: Reg,
227
mem: &MemArg,
228
opcode_rx: Option<u16>,
229
opcode_rxy: Option<u16>,
230
opcode_ril: Option<u16>,
231
add_trap: bool,
232
sink: &mut MachBuffer<Inst>,
233
emit_info: &EmitInfo,
234
state: &mut EmitState,
235
) {
236
let (mem_insts, mem) = mem_finalize(
237
mem,
238
state,
239
MemInstType {
240
have_d12: opcode_rx.is_some(),
241
have_d20: opcode_rxy.is_some(),
242
have_pcrel: opcode_ril.is_some(),
243
have_unaligned_pcrel: opcode_ril.is_some() && !add_trap,
244
have_index: true,
245
},
246
);
247
for inst in mem_insts.into_iter() {
248
inst.emit(sink, emit_info, state);
249
}
250
251
if add_trap {
252
if let Some(trap_code) = mem.get_flags().trap_code() {
253
sink.add_trap(trap_code);
254
}
255
}
256
257
match &mem {
258
&MemArg::BXD12 {
259
base, index, disp, ..
260
} => {
261
put(
262
sink,
263
&enc_rx(opcode_rx.unwrap(), rd, base, index, disp.bits()),
264
);
265
}
266
&MemArg::BXD20 {
267
base, index, disp, ..
268
} => {
269
put(
270
sink,
271
&enc_rxy(opcode_rxy.unwrap(), rd, base, index, disp.bits()),
272
);
273
}
274
&MemArg::Label { target } => {
275
sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);
276
put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
277
}
278
&MemArg::Constant { constant } => {
279
let target = sink.get_label_for_constant(constant);
280
sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);
281
put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
282
}
283
&MemArg::Symbol {
284
ref name, offset, ..
285
} => {
286
let reloc_offset = sink.cur_offset() + 2;
287
sink.add_reloc_at_offset(
288
reloc_offset,
289
Reloc::S390xPCRel32Dbl,
290
&**name,
291
(offset + 2).into(),
292
);
293
put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
294
}
295
_ => unreachable!(),
296
}
297
}
298
299
pub fn mem_rs_emit(
300
rd: Reg,
301
rn: Reg,
302
mem: &MemArg,
303
opcode_rs: Option<u16>,
304
opcode_rsy: Option<u16>,
305
add_trap: bool,
306
sink: &mut MachBuffer<Inst>,
307
emit_info: &EmitInfo,
308
state: &mut EmitState,
309
) {
310
let (mem_insts, mem) = mem_finalize(
311
mem,
312
state,
313
MemInstType {
314
have_d12: opcode_rs.is_some(),
315
have_d20: opcode_rsy.is_some(),
316
have_pcrel: false,
317
have_unaligned_pcrel: false,
318
have_index: false,
319
},
320
);
321
for inst in mem_insts.into_iter() {
322
inst.emit(sink, emit_info, state);
323
}
324
325
if add_trap {
326
if let Some(trap_code) = mem.get_flags().trap_code() {
327
sink.add_trap(trap_code);
328
}
329
}
330
331
match &mem {
332
&MemArg::BXD12 {
333
base, index, disp, ..
334
} => {
335
assert!(index == zero_reg());
336
put(sink, &enc_rs(opcode_rs.unwrap(), rd, rn, base, disp.bits()));
337
}
338
&MemArg::BXD20 {
339
base, index, disp, ..
340
} => {
341
assert!(index == zero_reg());
342
put(
343
sink,
344
&enc_rsy(opcode_rsy.unwrap(), rd, rn, base, disp.bits()),
345
);
346
}
347
_ => unreachable!(),
348
}
349
}
350
351
pub fn mem_imm8_emit(
352
imm: u8,
353
mem: &MemArg,
354
opcode_si: u16,
355
opcode_siy: u16,
356
add_trap: bool,
357
sink: &mut MachBuffer<Inst>,
358
emit_info: &EmitInfo,
359
state: &mut EmitState,
360
) {
361
let (mem_insts, mem) = mem_finalize(
362
mem,
363
state,
364
MemInstType {
365
have_d12: true,
366
have_d20: true,
367
have_pcrel: false,
368
have_unaligned_pcrel: false,
369
have_index: false,
370
},
371
);
372
for inst in mem_insts.into_iter() {
373
inst.emit(sink, emit_info, state);
374
}
375
376
if add_trap {
377
if let Some(trap_code) = mem.get_flags().trap_code() {
378
sink.add_trap(trap_code);
379
}
380
}
381
382
match &mem {
383
&MemArg::BXD12 {
384
base, index, disp, ..
385
} => {
386
assert!(index == zero_reg());
387
put(sink, &enc_si(opcode_si, base, disp.bits(), imm));
388
}
389
&MemArg::BXD20 {
390
base, index, disp, ..
391
} => {
392
assert!(index == zero_reg());
393
put(sink, &enc_siy(opcode_siy, base, disp.bits(), imm));
394
}
395
_ => unreachable!(),
396
}
397
}
398
399
pub fn mem_imm16_emit(
400
imm: i16,
401
mem: &MemArg,
402
opcode_sil: u16,
403
add_trap: bool,
404
sink: &mut MachBuffer<Inst>,
405
emit_info: &EmitInfo,
406
state: &mut EmitState,
407
) {
408
let (mem_insts, mem) = mem_finalize(
409
mem,
410
state,
411
MemInstType {
412
have_d12: true,
413
have_d20: false,
414
have_pcrel: false,
415
have_unaligned_pcrel: false,
416
have_index: false,
417
},
418
);
419
for inst in mem_insts.into_iter() {
420
inst.emit(sink, emit_info, state);
421
}
422
423
if add_trap {
424
if let Some(trap_code) = mem.get_flags().trap_code() {
425
sink.add_trap(trap_code);
426
}
427
}
428
429
match &mem {
430
&MemArg::BXD12 {
431
base, index, disp, ..
432
} => {
433
assert!(index == zero_reg());
434
put(sink, &enc_sil(opcode_sil, base, disp.bits(), imm));
435
}
436
_ => unreachable!(),
437
}
438
}
439
440
pub fn mem_vrx_emit(
441
rd: Reg,
442
mem: &MemArg,
443
opcode: u16,
444
m3: u8,
445
add_trap: bool,
446
sink: &mut MachBuffer<Inst>,
447
emit_info: &EmitInfo,
448
state: &mut EmitState,
449
) {
450
let (mem_insts, mem) = mem_finalize(
451
mem,
452
state,
453
MemInstType {
454
have_d12: true,
455
have_d20: false,
456
have_pcrel: false,
457
have_unaligned_pcrel: false,
458
have_index: true,
459
},
460
);
461
for inst in mem_insts.into_iter() {
462
inst.emit(sink, emit_info, state);
463
}
464
465
if add_trap {
466
if let Some(trap_code) = mem.get_flags().trap_code() {
467
sink.add_trap(trap_code);
468
}
469
}
470
471
match &mem {
472
&MemArg::BXD12 {
473
base, index, disp, ..
474
} => {
475
put(sink, &enc_vrx(opcode, rd, base, index, disp.bits(), m3));
476
}
477
_ => unreachable!(),
478
}
479
}
480
481
//=============================================================================
482
// Instructions and subcomponents: emission
483
484
fn machreg_to_gpr(m: Reg) -> u8 {
485
assert_eq!(m.class(), RegClass::Int);
486
m.to_real_reg().unwrap().hw_enc()
487
}
488
489
fn machreg_to_vr(m: Reg) -> u8 {
490
assert_eq!(m.class(), RegClass::Float);
491
m.to_real_reg().unwrap().hw_enc()
492
}
493
494
fn machreg_to_fpr(m: Reg) -> u8 {
495
assert!(is_fpr(m));
496
m.to_real_reg().unwrap().hw_enc()
497
}
498
499
fn machreg_to_gpr_or_fpr(m: Reg) -> u8 {
500
let reg = m.to_real_reg().unwrap().hw_enc();
501
assert!(reg < 16);
502
reg
503
}
504
505
fn rxb(v1: Option<Reg>, v2: Option<Reg>, v3: Option<Reg>, v4: Option<Reg>) -> u8 {
506
let mut rxb = 0;
507
508
let is_high_vr = |reg| -> bool {
509
if let Some(reg) = reg {
510
if !is_fpr(reg) {
511
return true;
512
}
513
}
514
false
515
};
516
517
if is_high_vr(v1) {
518
rxb = rxb | 8;
519
}
520
if is_high_vr(v2) {
521
rxb = rxb | 4;
522
}
523
if is_high_vr(v3) {
524
rxb = rxb | 2;
525
}
526
if is_high_vr(v4) {
527
rxb = rxb | 1;
528
}
529
530
rxb
531
}
532
533
/// E-type instructions.
534
///
535
/// 15
536
/// opcode
537
/// 0
538
///
539
fn enc_e(opcode: u16) -> [u8; 2] {
540
let mut enc: [u8; 2] = [0; 2];
541
let opcode1 = ((opcode >> 8) & 0xff) as u8;
542
let opcode2 = (opcode & 0xff) as u8;
543
544
enc[0] = opcode1;
545
enc[1] = opcode2;
546
enc
547
}
548
549
/// RIa-type instructions.
550
///
551
/// 31 23 19 15
552
/// opcode1 r1 opcode2 i2
553
/// 24 20 16 0
554
///
555
fn enc_ri_a(opcode: u16, r1: Reg, i2: u16) -> [u8; 4] {
556
let mut enc: [u8; 4] = [0; 4];
557
let opcode1 = ((opcode >> 4) & 0xff) as u8;
558
let opcode2 = (opcode & 0xf) as u8;
559
let r1 = machreg_to_gpr(r1) & 0x0f;
560
561
enc[0] = opcode1;
562
enc[1] = r1 << 4 | opcode2;
563
enc[2..].copy_from_slice(&i2.to_be_bytes());
564
enc
565
}
566
567
/// RIb-type instructions.
568
///
569
/// 31 23 19 15
570
/// opcode1 r1 opcode2 ri2
571
/// 24 20 16 0
572
///
573
fn enc_ri_b(opcode: u16, r1: Reg, ri2: i32) -> [u8; 4] {
574
let mut enc: [u8; 4] = [0; 4];
575
let opcode1 = ((opcode >> 4) & 0xff) as u8;
576
let opcode2 = (opcode & 0xf) as u8;
577
let r1 = machreg_to_gpr(r1) & 0x0f;
578
let ri2 = ((ri2 >> 1) & 0xffff) as u16;
579
580
enc[0] = opcode1;
581
enc[1] = r1 << 4 | opcode2;
582
enc[2..].copy_from_slice(&ri2.to_be_bytes());
583
enc
584
}
585
586
/// RIc-type instructions.
587
///
588
/// 31 23 19 15
589
/// opcode1 m1 opcode2 ri2
590
/// 24 20 16 0
591
///
592
fn enc_ri_c(opcode: u16, m1: u8, ri2: i32) -> [u8; 4] {
593
let mut enc: [u8; 4] = [0; 4];
594
let opcode1 = ((opcode >> 4) & 0xff) as u8;
595
let opcode2 = (opcode & 0xf) as u8;
596
let m1 = m1 & 0x0f;
597
let ri2 = ((ri2 >> 1) & 0xffff) as u16;
598
599
enc[0] = opcode1;
600
enc[1] = m1 << 4 | opcode2;
601
enc[2..].copy_from_slice(&ri2.to_be_bytes());
602
enc
603
}
604
605
/// RIEa-type instructions.
606
///
607
/// 47 39 35 31 15 11 7
608
/// opcode1 r1 -- i2 m3 -- opcode2
609
/// 40 36 32 16 12 8 0
610
///
611
fn enc_rie_a(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {
612
let mut enc: [u8; 6] = [0; 6];
613
let opcode1 = ((opcode >> 8) & 0xff) as u8;
614
let opcode2 = (opcode & 0xff) as u8;
615
let r1 = machreg_to_gpr(r1) & 0x0f;
616
let m3 = m3 & 0x0f;
617
618
enc[0] = opcode1;
619
enc[1] = r1 << 4;
620
enc[2..4].copy_from_slice(&i2.to_be_bytes());
621
enc[4] = m3 << 4;
622
enc[5] = opcode2;
623
enc
624
}
625
626
/// RIEd-type instructions.
627
///
628
/// 47 39 35 31 15 7
629
/// opcode1 r1 r3 i2 -- opcode2
630
/// 40 36 32 16 8 0
631
///
632
fn enc_rie_d(opcode: u16, r1: Reg, r3: Reg, i2: u16) -> [u8; 6] {
633
let mut enc: [u8; 6] = [0; 6];
634
let opcode1 = ((opcode >> 8) & 0xff) as u8;
635
let opcode2 = (opcode & 0xff) as u8;
636
let r1 = machreg_to_gpr(r1) & 0x0f;
637
let r3 = machreg_to_gpr(r3) & 0x0f;
638
639
enc[0] = opcode1;
640
enc[1] = r1 << 4 | r3;
641
enc[2..4].copy_from_slice(&i2.to_be_bytes());
642
enc[5] = opcode2;
643
enc
644
}
645
646
/// RIEf-type instructions.
647
///
648
/// 47 39 35 31 23 15 7
649
/// opcode1 r1 r2 i3 i4 i5 opcode2
650
/// 40 36 32 24 16 8 0
651
///
652
fn enc_rie_f(opcode: u16, r1: Reg, r2: Reg, i3: u8, i4: u8, i5: u8) -> [u8; 6] {
653
let mut enc: [u8; 6] = [0; 6];
654
let opcode1 = ((opcode >> 8) & 0xff) as u8;
655
let opcode2 = (opcode & 0xff) as u8;
656
let r1 = machreg_to_gpr(r1) & 0x0f;
657
let r2 = machreg_to_gpr(r2) & 0x0f;
658
659
enc[0] = opcode1;
660
enc[1] = r1 << 4 | r2;
661
enc[2] = i3;
662
enc[3] = i4;
663
enc[4] = i5;
664
enc[5] = opcode2;
665
enc
666
}
667
668
/// RIEg-type instructions.
669
///
670
/// 47 39 35 31 15 7
671
/// opcode1 r1 m3 i2 -- opcode2
672
/// 40 36 32 16 8 0
673
///
674
fn enc_rie_g(opcode: u16, r1: Reg, i2: u16, m3: u8) -> [u8; 6] {
675
let mut enc: [u8; 6] = [0; 6];
676
let opcode1 = ((opcode >> 8) & 0xff) as u8;
677
let opcode2 = (opcode & 0xff) as u8;
678
let r1 = machreg_to_gpr(r1) & 0x0f;
679
let m3 = m3 & 0x0f;
680
681
enc[0] = opcode1;
682
enc[1] = r1 << 4 | m3;
683
enc[2..4].copy_from_slice(&i2.to_be_bytes());
684
enc[5] = opcode2;
685
enc
686
}
687
688
/// RILa-type instructions.
689
///
690
/// 47 39 35 31
691
/// opcode1 r1 opcode2 i2
692
/// 40 36 32 0
693
///
694
fn enc_ril_a(opcode: u16, r1: Reg, i2: u32) -> [u8; 6] {
695
let mut enc: [u8; 6] = [0; 6];
696
let opcode1 = ((opcode >> 4) & 0xff) as u8;
697
let opcode2 = (opcode & 0xf) as u8;
698
let r1 = machreg_to_gpr(r1) & 0x0f;
699
700
enc[0] = opcode1;
701
enc[1] = r1 << 4 | opcode2;
702
enc[2..].copy_from_slice(&i2.to_be_bytes());
703
enc
704
}
705
706
/// RILb-type instructions.
707
///
708
/// 47 39 35 31
709
/// opcode1 r1 opcode2 ri2
710
/// 40 36 32 0
711
///
712
fn enc_ril_b(opcode: u16, r1: Reg, ri2: u32) -> [u8; 6] {
713
let mut enc: [u8; 6] = [0; 6];
714
let opcode1 = ((opcode >> 4) & 0xff) as u8;
715
let opcode2 = (opcode & 0xf) as u8;
716
let r1 = machreg_to_gpr(r1) & 0x0f;
717
let ri2 = ri2 >> 1;
718
719
enc[0] = opcode1;
720
enc[1] = r1 << 4 | opcode2;
721
enc[2..].copy_from_slice(&ri2.to_be_bytes());
722
enc
723
}
724
725
/// RILc-type instructions.
726
///
727
/// 47 39 35 31
728
/// opcode1 m1 opcode2 i2
729
/// 40 36 32 0
730
///
731
fn enc_ril_c(opcode: u16, m1: u8, ri2: u32) -> [u8; 6] {
732
let mut enc: [u8; 6] = [0; 6];
733
let opcode1 = ((opcode >> 4) & 0xff) as u8;
734
let opcode2 = (opcode & 0xf) as u8;
735
let m1 = m1 & 0x0f;
736
let ri2 = ri2 >> 1;
737
738
enc[0] = opcode1;
739
enc[1] = m1 << 4 | opcode2;
740
enc[2..].copy_from_slice(&ri2.to_be_bytes());
741
enc
742
}
743
744
/// RR-type instructions.
745
///
746
/// 15 7 3
747
/// opcode r1 r2
748
/// 8 4 0
749
///
750
fn enc_rr(opcode: u16, r1: Reg, r2: Reg) -> [u8; 2] {
751
let mut enc: [u8; 2] = [0; 2];
752
let opcode = (opcode & 0xff) as u8;
753
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
754
let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
755
756
enc[0] = opcode;
757
enc[1] = r1 << 4 | r2;
758
enc
759
}
760
761
/// RRD-type instructions.
762
///
763
/// 31 15 11 7 3
764
/// opcode r1 -- r3 r2
765
/// 16 12 8 4 0
766
///
767
fn enc_rrd(opcode: u16, r1: Reg, r2: Reg, r3: Reg) -> [u8; 4] {
768
let mut enc: [u8; 4] = [0; 4];
769
let opcode1 = ((opcode >> 8) & 0xff) as u8;
770
let opcode2 = (opcode & 0xff) as u8;
771
let r1 = machreg_to_fpr(r1) & 0x0f;
772
let r2 = machreg_to_fpr(r2) & 0x0f;
773
let r3 = machreg_to_fpr(r3) & 0x0f;
774
775
enc[0] = opcode1;
776
enc[1] = opcode2;
777
enc[2] = r1 << 4;
778
enc[3] = r3 << 4 | r2;
779
enc
780
}
781
782
/// RRE-type instructions.
783
///
784
/// 31 15 7 3
785
/// opcode -- r1 r2
786
/// 16 8 4 0
787
///
788
fn enc_rre(opcode: u16, r1: Reg, r2: Reg) -> [u8; 4] {
789
let mut enc: [u8; 4] = [0; 4];
790
let opcode1 = ((opcode >> 8) & 0xff) as u8;
791
let opcode2 = (opcode & 0xff) as u8;
792
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
793
let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
794
795
enc[0] = opcode1;
796
enc[1] = opcode2;
797
enc[3] = r1 << 4 | r2;
798
enc
799
}
800
801
/// RRFa/b-type instructions.
802
///
803
/// 31 15 11 7 3
804
/// opcode r3 m4 r1 r2
805
/// 16 12 8 4 0
806
///
807
fn enc_rrf_ab(opcode: u16, r1: Reg, r2: Reg, r3: Reg, m4: u8) -> [u8; 4] {
808
let mut enc: [u8; 4] = [0; 4];
809
let opcode1 = ((opcode >> 8) & 0xff) as u8;
810
let opcode2 = (opcode & 0xff) as u8;
811
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
812
let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
813
let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
814
let m4 = m4 & 0x0f;
815
816
enc[0] = opcode1;
817
enc[1] = opcode2;
818
enc[2] = r3 << 4 | m4;
819
enc[3] = r1 << 4 | r2;
820
enc
821
}
822
823
/// RRFc/d/e-type instructions.
824
///
825
/// 31 15 11 7 3
826
/// opcode m3 m4 r1 r2
827
/// 16 12 8 4 0
828
///
829
fn enc_rrf_cde(opcode: u16, r1: Reg, r2: Reg, m3: u8, m4: u8) -> [u8; 4] {
830
let mut enc: [u8; 4] = [0; 4];
831
let opcode1 = ((opcode >> 8) & 0xff) as u8;
832
let opcode2 = (opcode & 0xff) as u8;
833
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
834
let r2 = machreg_to_gpr_or_fpr(r2) & 0x0f;
835
let m3 = m3 & 0x0f;
836
let m4 = m4 & 0x0f;
837
838
enc[0] = opcode1;
839
enc[1] = opcode2;
840
enc[2] = m3 << 4 | m4;
841
enc[3] = r1 << 4 | r2;
842
enc
843
}
844
845
/// RS-type instructions.
846
///
847
/// 31 23 19 15 11
848
/// opcode r1 r3 b2 d2
849
/// 24 20 16 12 0
850
///
851
fn enc_rs(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 4] {
852
let opcode = (opcode & 0xff) as u8;
853
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
854
let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
855
let b2 = machreg_to_gpr(b2) & 0x0f;
856
let d2_lo = (d2 & 0xff) as u8;
857
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
858
859
let mut enc: [u8; 4] = [0; 4];
860
enc[0] = opcode;
861
enc[1] = r1 << 4 | r3;
862
enc[2] = b2 << 4 | d2_hi;
863
enc[3] = d2_lo;
864
enc
865
}
866
867
/// RSY-type instructions.
868
///
869
/// 47 39 35 31 27 15 7
870
/// opcode1 r1 r3 b2 dl2 dh2 opcode2
871
/// 40 36 32 28 16 8 0
872
///
873
fn enc_rsy(opcode: u16, r1: Reg, r3: Reg, b2: Reg, d2: u32) -> [u8; 6] {
874
let opcode1 = ((opcode >> 8) & 0xff) as u8;
875
let opcode2 = (opcode & 0xff) as u8;
876
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
877
let r3 = machreg_to_gpr_or_fpr(r3) & 0x0f;
878
let b2 = machreg_to_gpr(b2) & 0x0f;
879
let dl2_lo = (d2 & 0xff) as u8;
880
let dl2_hi = ((d2 >> 8) & 0x0f) as u8;
881
let dh2 = ((d2 >> 12) & 0xff) as u8;
882
883
let mut enc: [u8; 6] = [0; 6];
884
enc[0] = opcode1;
885
enc[1] = r1 << 4 | r3;
886
enc[2] = b2 << 4 | dl2_hi;
887
enc[3] = dl2_lo;
888
enc[4] = dh2;
889
enc[5] = opcode2;
890
enc
891
}
892
893
/// RX-type instructions.
894
///
895
/// 31 23 19 15 11
896
/// opcode r1 x2 b2 d2
897
/// 24 20 16 12 0
898
///
899
fn enc_rx(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 4] {
900
let opcode = (opcode & 0xff) as u8;
901
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
902
let b2 = machreg_to_gpr(b2) & 0x0f;
903
let x2 = machreg_to_gpr(x2) & 0x0f;
904
let d2_lo = (d2 & 0xff) as u8;
905
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
906
907
let mut enc: [u8; 4] = [0; 4];
908
enc[0] = opcode;
909
enc[1] = r1 << 4 | x2;
910
enc[2] = b2 << 4 | d2_hi;
911
enc[3] = d2_lo;
912
enc
913
}
914
915
/// RXY-type instructions.
916
///
917
/// 47 39 35 31 27 15 7
918
/// opcode1 r1 x2 b2 dl2 dh2 opcode2
919
/// 40 36 32 28 16 8 0
920
///
921
fn enc_rxy(opcode: u16, r1: Reg, b2: Reg, x2: Reg, d2: u32) -> [u8; 6] {
922
let opcode1 = ((opcode >> 8) & 0xff) as u8;
923
let opcode2 = (opcode & 0xff) as u8;
924
let r1 = machreg_to_gpr_or_fpr(r1) & 0x0f;
925
let b2 = machreg_to_gpr(b2) & 0x0f;
926
let x2 = machreg_to_gpr(x2) & 0x0f;
927
let dl2_lo = (d2 & 0xff) as u8;
928
let dl2_hi = ((d2 >> 8) & 0x0f) as u8;
929
let dh2 = ((d2 >> 12) & 0xff) as u8;
930
931
let mut enc: [u8; 6] = [0; 6];
932
enc[0] = opcode1;
933
enc[1] = r1 << 4 | x2;
934
enc[2] = b2 << 4 | dl2_hi;
935
enc[3] = dl2_lo;
936
enc[4] = dh2;
937
enc[5] = opcode2;
938
enc
939
}
940
941
/// SI-type instructions.
942
///
943
/// 31 23 15 11
944
/// opcode i2 b1 d1
945
/// 24 16 12 0
946
///
947
fn enc_si(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 4] {
948
let opcode = (opcode & 0xff) as u8;
949
let b1 = machreg_to_gpr(b1) & 0x0f;
950
let d1_lo = (d1 & 0xff) as u8;
951
let d1_hi = ((d1 >> 8) & 0x0f) as u8;
952
953
let mut enc: [u8; 4] = [0; 4];
954
enc[0] = opcode;
955
enc[1] = i2;
956
enc[2] = b1 << 4 | d1_hi;
957
enc[3] = d1_lo;
958
enc
959
}
960
961
/// SIL-type instructions.
962
///
963
/// 47 31 27 15
964
/// opcode b1 d1 i2
965
/// 32 28 16 0
966
///
967
fn enc_sil(opcode: u16, b1: Reg, d1: u32, i2: i16) -> [u8; 6] {
968
let opcode1 = ((opcode >> 8) & 0xff) as u8;
969
let opcode2 = (opcode & 0xff) as u8;
970
let b1 = machreg_to_gpr(b1) & 0x0f;
971
let d1_lo = (d1 & 0xff) as u8;
972
let d1_hi = ((d1 >> 8) & 0x0f) as u8;
973
974
let mut enc: [u8; 6] = [0; 6];
975
enc[0] = opcode1;
976
enc[1] = opcode2;
977
enc[2] = b1 << 4 | d1_hi;
978
enc[3] = d1_lo;
979
enc[4..].copy_from_slice(&i2.to_be_bytes());
980
enc
981
}
982
983
/// SIY-type instructions.
984
///
985
/// 47 39 31 27 15 7
986
/// opcode1 i2 b1 dl1 dh1 opcode2
987
/// 40 32 28 16 8 0
988
///
989
fn enc_siy(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 6] {
990
let opcode1 = ((opcode >> 8) & 0xff) as u8;
991
let opcode2 = (opcode & 0xff) as u8;
992
let b1 = machreg_to_gpr(b1) & 0x0f;
993
let dl1_lo = (d1 & 0xff) as u8;
994
let dl1_hi = ((d1 >> 8) & 0x0f) as u8;
995
let dh1 = ((d1 >> 12) & 0xff) as u8;
996
997
let mut enc: [u8; 6] = [0; 6];
998
enc[0] = opcode1;
999
enc[1] = i2;
1000
enc[2] = b1 << 4 | dl1_hi;
1001
enc[3] = dl1_lo;
1002
enc[4] = dh1;
1003
enc[5] = opcode2;
1004
enc
1005
}
1006
1007
/// VRIa-type instructions.
1008
///
1009
/// 47 39 35 31 15 11 7
1010
/// opcode1 v1 - i2 m3 rxb opcode2
1011
/// 40 36 32 16 12 8 0
1012
///
1013
fn enc_vri_a(opcode: u16, v1: Reg, i2: u16, m3: u8) -> [u8; 6] {
1014
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1015
let opcode2 = (opcode & 0xff) as u8;
1016
let rxb = rxb(Some(v1), None, None, None);
1017
let v1 = machreg_to_vr(v1) & 0x0f;
1018
let m3 = m3 & 0x0f;
1019
1020
let mut enc: [u8; 6] = [0; 6];
1021
enc[0] = opcode1;
1022
enc[1] = v1 << 4;
1023
enc[2..4].copy_from_slice(&i2.to_be_bytes());
1024
enc[4] = m3 << 4 | rxb;
1025
enc[5] = opcode2;
1026
enc
1027
}
1028
1029
/// VRIb-type instructions.
1030
///
1031
/// 47 39 35 31 23 15 11 7
1032
/// opcode1 v1 - i2 i3 m4 rxb opcode2
1033
/// 40 36 32 24 16 12 8 0
1034
///
1035
fn enc_vri_b(opcode: u16, v1: Reg, i2: u8, i3: u8, m4: u8) -> [u8; 6] {
1036
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1037
let opcode2 = (opcode & 0xff) as u8;
1038
let rxb = rxb(Some(v1), None, None, None);
1039
let v1 = machreg_to_vr(v1) & 0x0f;
1040
let m4 = m4 & 0x0f;
1041
1042
let mut enc: [u8; 6] = [0; 6];
1043
enc[0] = opcode1;
1044
enc[1] = v1 << 4;
1045
enc[2] = i2;
1046
enc[3] = i3;
1047
enc[4] = m4 << 4 | rxb;
1048
enc[5] = opcode2;
1049
enc
1050
}
1051
1052
/// VRIc-type instructions.
1053
///
1054
/// 47 39 35 31 15 11 7
1055
/// opcode1 v1 v3 i2 m4 rxb opcode2
1056
/// 40 36 32 16 12 8 0
1057
///
1058
fn enc_vri_c(opcode: u16, v1: Reg, i2: u16, v3: Reg, m4: u8) -> [u8; 6] {
1059
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1060
let opcode2 = (opcode & 0xff) as u8;
1061
let rxb = rxb(Some(v1), Some(v3), None, None);
1062
let v1 = machreg_to_vr(v1) & 0x0f;
1063
let v3 = machreg_to_vr(v3) & 0x0f;
1064
let m4 = m4 & 0x0f;
1065
1066
let mut enc: [u8; 6] = [0; 6];
1067
enc[0] = opcode1;
1068
enc[1] = v1 << 4 | v3;
1069
enc[2..4].copy_from_slice(&i2.to_be_bytes());
1070
enc[4] = m4 << 4 | rxb;
1071
enc[5] = opcode2;
1072
enc
1073
}
1074
1075
/// VRIk-type instructions.
1076
///
1077
/// 47 39 35 31 27 23 15 11 7
1078
/// opcode1 v1 v2 v3 - i5 v4 rxb opcode2
1079
/// 40 36 32 28 24 16 12 8 0
1080
///
1081
fn enc_vri_k(opcode: u16, i5: u8, v1: Reg, v2: Reg, v3: Reg, v4: Reg) -> [u8; 6] {
1082
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1083
let opcode2 = (opcode & 0xff) as u8;
1084
let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));
1085
let v1 = machreg_to_vr(v1) & 0x0f;
1086
let v2 = machreg_to_vr(v2) & 0x0f;
1087
let v3 = machreg_to_vr(v3) & 0x0f;
1088
let v4 = machreg_to_vr(v4) & 0x0f;
1089
1090
let mut enc: [u8; 6] = [0; 6];
1091
enc[0] = opcode1;
1092
enc[1] = v1 << 4 | v2;
1093
enc[2] = v3 << 4;
1094
enc[3] = i5;
1095
enc[4] = v4 << 4 | rxb;
1096
enc[5] = opcode2;
1097
enc
1098
}
1099
1100
/// VRRa-type instructions.
1101
///
1102
/// 47 39 35 31 23 19 15 11 7
1103
/// opcode1 v1 v2 - m5 m3 m2 rxb opcode2
1104
/// 40 36 32 24 20 16 12 8 0
1105
///
1106
fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [u8; 6] {
1107
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1108
let opcode2 = (opcode & 0xff) as u8;
1109
let rxb = rxb(Some(v1), Some(v2), None, None);
1110
let v1 = machreg_to_vr(v1) & 0x0f;
1111
let v2 = machreg_to_vr(v2) & 0x0f;
1112
let m3 = m3 & 0x0f;
1113
let m4 = m4 & 0x0f;
1114
let m5 = m5 & 0x0f;
1115
1116
let mut enc: [u8; 6] = [0; 6];
1117
enc[0] = opcode1;
1118
enc[1] = v1 << 4 | v2;
1119
enc[2] = 0;
1120
enc[3] = m5 << 4 | m4;
1121
enc[4] = m3 << 4 | rxb;
1122
enc[5] = opcode2;
1123
enc
1124
}
1125
1126
/// VRRb-type instructions.
1127
///
1128
/// 47 39 35 31 27 23 19 15 11 7
1129
/// opcode1 v1 v2 v3 - m5 - m4 rxb opcode2
1130
/// 40 36 32 28 24 20 16 12 8 0
1131
///
1132
fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] {
1133
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1134
let opcode2 = (opcode & 0xff) as u8;
1135
let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1136
let v1 = machreg_to_vr(v1) & 0x0f;
1137
let v2 = machreg_to_vr(v2) & 0x0f;
1138
let v3 = machreg_to_vr(v3) & 0x0f;
1139
let m4 = m4 & 0x0f;
1140
let m5 = m5 & 0x0f;
1141
1142
let mut enc: [u8; 6] = [0; 6];
1143
enc[0] = opcode1;
1144
enc[1] = v1 << 4 | v2;
1145
enc[2] = v3 << 4;
1146
enc[3] = m5 << 4;
1147
enc[4] = m4 << 4 | rxb;
1148
enc[5] = opcode2;
1149
enc
1150
}
1151
1152
/// VRRc-type instructions.
1153
///
1154
/// 47 39 35 31 27 23 19 15 11 7
1155
/// opcode1 v1 v2 v3 - m6 m5 m4 rxb opcode2
1156
/// 40 36 32 28 24 20 16 12 8 0
1157
///
1158
fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] {
1159
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1160
let opcode2 = (opcode & 0xff) as u8;
1161
let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1162
let v1 = machreg_to_vr(v1) & 0x0f;
1163
let v2 = machreg_to_vr(v2) & 0x0f;
1164
let v3 = machreg_to_vr(v3) & 0x0f;
1165
let m4 = m4 & 0x0f;
1166
let m5 = m5 & 0x0f;
1167
let m6 = m6 & 0x0f;
1168
1169
let mut enc: [u8; 6] = [0; 6];
1170
enc[0] = opcode1;
1171
enc[1] = v1 << 4 | v2;
1172
enc[2] = v3 << 4;
1173
enc[3] = m6 << 4 | m5;
1174
enc[4] = m4 << 4 | rxb;
1175
enc[5] = opcode2;
1176
enc
1177
}
1178
1179
/// VRRd-type instructions.
1180
///
1181
/// 47 39 35 31 27 23 19 15 11 7
1182
/// opcode1 v1 v2 v3 m5 m6 - v4 rxb opcode2
1183
/// 40 36 32 28 24 20 16 12 8 0
1184
///
1185
fn enc_vrr_d(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {
1186
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1187
let opcode2 = (opcode & 0xff) as u8;
1188
let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));
1189
let v1 = machreg_to_vr(v1) & 0x0f;
1190
let v2 = machreg_to_vr(v2) & 0x0f;
1191
let v3 = machreg_to_vr(v3) & 0x0f;
1192
let v4 = machreg_to_vr(v4) & 0x0f;
1193
let m5 = m5 & 0x0f;
1194
let m6 = m6 & 0x0f;
1195
1196
let mut enc: [u8; 6] = [0; 6];
1197
enc[0] = opcode1;
1198
enc[1] = v1 << 4 | v2;
1199
enc[2] = v3 << 4 | m5;
1200
enc[3] = m6 << 4;
1201
enc[4] = v4 << 4 | rxb;
1202
enc[5] = opcode2;
1203
enc
1204
}
1205
1206
/// VRRe-type instructions.
1207
///
1208
/// 47 39 35 31 27 23 19 15 11 7
1209
/// opcode1 v1 v2 v3 m6 - m5 v4 rxb opcode2
1210
/// 40 36 32 28 24 20 16 12 8 0
1211
///
1212
fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {
1213
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1214
let opcode2 = (opcode & 0xff) as u8;
1215
let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));
1216
let v1 = machreg_to_vr(v1) & 0x0f;
1217
let v2 = machreg_to_vr(v2) & 0x0f;
1218
let v3 = machreg_to_vr(v3) & 0x0f;
1219
let v4 = machreg_to_vr(v4) & 0x0f;
1220
let m5 = m5 & 0x0f;
1221
let m6 = m6 & 0x0f;
1222
1223
let mut enc: [u8; 6] = [0; 6];
1224
enc[0] = opcode1;
1225
enc[1] = v1 << 4 | v2;
1226
enc[2] = v3 << 4 | m6;
1227
enc[3] = m5;
1228
enc[4] = v4 << 4 | rxb;
1229
enc[5] = opcode2;
1230
enc
1231
}
1232
1233
/// VRRf-type instructions.
1234
///
1235
/// 47 39 35 31 27 11 7
1236
/// opcode1 v1 r2 r3 - rxb opcode2
1237
/// 40 36 32 28 12 8 0
1238
///
1239
fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] {
1240
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1241
let opcode2 = (opcode & 0xff) as u8;
1242
let rxb = rxb(Some(v1), None, None, None);
1243
let v1 = machreg_to_vr(v1) & 0x0f;
1244
let r2 = machreg_to_gpr(r2) & 0x0f;
1245
let r3 = machreg_to_gpr(r3) & 0x0f;
1246
1247
let mut enc: [u8; 6] = [0; 6];
1248
enc[0] = opcode1;
1249
enc[1] = v1 << 4 | r2;
1250
enc[2] = r3 << 4;
1251
enc[4] = rxb;
1252
enc[5] = opcode2;
1253
enc
1254
}
1255
1256
/// VRSa-type instructions.
1257
///
1258
/// 47 39 35 31 27 15 11 7
1259
/// opcode1 v1 v3 b2 d2 m4 rxb opcode2
1260
/// 40 36 32 28 16 12 8 0
1261
///
1262
fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1263
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1264
let opcode2 = (opcode & 0xff) as u8;
1265
let rxb = rxb(Some(v1), Some(v3), None, None);
1266
let v1 = machreg_to_vr(v1) & 0x0f;
1267
let b2 = machreg_to_gpr(b2) & 0x0f;
1268
let v3 = machreg_to_vr(v3) & 0x0f;
1269
let d2_lo = (d2 & 0xff) as u8;
1270
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1271
let m4 = m4 & 0x0f;
1272
1273
let mut enc: [u8; 6] = [0; 6];
1274
enc[0] = opcode1;
1275
enc[1] = v1 << 4 | v3;
1276
enc[2] = b2 << 4 | d2_hi;
1277
enc[3] = d2_lo;
1278
enc[4] = m4 << 4 | rxb;
1279
enc[5] = opcode2;
1280
enc
1281
}
1282
1283
/// VRSb-type instructions.
1284
///
1285
/// 47 39 35 31 27 15 11 7
1286
/// opcode1 v1 r3 b2 d2 m4 rxb opcode2
1287
/// 40 36 32 28 16 12 8 0
1288
///
1289
fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] {
1290
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1291
let opcode2 = (opcode & 0xff) as u8;
1292
let rxb = rxb(Some(v1), None, None, None);
1293
let v1 = machreg_to_vr(v1) & 0x0f;
1294
let b2 = machreg_to_gpr(b2) & 0x0f;
1295
let r3 = machreg_to_gpr(r3) & 0x0f;
1296
let d2_lo = (d2 & 0xff) as u8;
1297
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1298
let m4 = m4 & 0x0f;
1299
1300
let mut enc: [u8; 6] = [0; 6];
1301
enc[0] = opcode1;
1302
enc[1] = v1 << 4 | r3;
1303
enc[2] = b2 << 4 | d2_hi;
1304
enc[3] = d2_lo;
1305
enc[4] = m4 << 4 | rxb;
1306
enc[5] = opcode2;
1307
enc
1308
}
1309
1310
/// VRSc-type instructions.
1311
///
1312
/// 47 39 35 31 27 15 11 7
1313
/// opcode1 r1 v3 b2 d2 m4 rxb opcode2
1314
/// 40 36 32 28 16 12 8 0
1315
///
1316
fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1317
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1318
let opcode2 = (opcode & 0xff) as u8;
1319
let rxb = rxb(None, Some(v3), None, None);
1320
let r1 = machreg_to_gpr(r1) & 0x0f;
1321
let b2 = machreg_to_gpr(b2) & 0x0f;
1322
let v3 = machreg_to_vr(v3) & 0x0f;
1323
let d2_lo = (d2 & 0xff) as u8;
1324
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1325
let m4 = m4 & 0x0f;
1326
1327
let mut enc: [u8; 6] = [0; 6];
1328
enc[0] = opcode1;
1329
enc[1] = r1 << 4 | v3;
1330
enc[2] = b2 << 4 | d2_hi;
1331
enc[3] = d2_lo;
1332
enc[4] = m4 << 4 | rxb;
1333
enc[5] = opcode2;
1334
enc
1335
}
1336
1337
/// VRX-type instructions.
1338
///
1339
/// 47 39 35 31 27 15 11 7
1340
/// opcode1 v1 x2 b2 d2 m3 rxb opcode2
1341
/// 40 36 32 28 16 12 8 0
1342
///
1343
fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] {
1344
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1345
let opcode2 = (opcode & 0xff) as u8;
1346
let rxb = rxb(Some(v1), None, None, None);
1347
let v1 = machreg_to_vr(v1) & 0x0f;
1348
let b2 = machreg_to_gpr(b2) & 0x0f;
1349
let x2 = machreg_to_gpr(x2) & 0x0f;
1350
let d2_lo = (d2 & 0xff) as u8;
1351
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1352
let m3 = m3 & 0x0f;
1353
1354
let mut enc: [u8; 6] = [0; 6];
1355
enc[0] = opcode1;
1356
enc[1] = v1 << 4 | x2;
1357
enc[2] = b2 << 4 | d2_hi;
1358
enc[3] = d2_lo;
1359
enc[4] = m3 << 4 | rxb;
1360
enc[5] = opcode2;
1361
enc
1362
}
1363
1364
/// Emit encoding to sink.
1365
fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {
1366
for byte in enc {
1367
sink.put1(*byte);
1368
}
1369
}
1370
1371
/// Emit encoding to sink, adding a trap on the last byte.
1372
fn put_with_trap(sink: &mut MachBuffer<Inst>, enc: &[u8], trap_code: TrapCode) {
1373
let len = enc.len();
1374
for i in 0..len - 1 {
1375
sink.put1(enc[i]);
1376
}
1377
sink.add_trap(trap_code);
1378
sink.put1(enc[len - 1]);
1379
}
1380
1381
/// State carried between emissions of a sequence of instructions.
1382
#[derive(Default, Clone, Debug)]
1383
pub struct EmitState {
1384
/// Offset from the actual SP to the "nominal SP". The latter is defined
1385
/// as the value the stack pointer has after the prolog. This offset is
1386
/// normally always zero, except during a call sequence using the tail-call
1387
/// ABI, between the AllocateArgs and the actual call instruction.
1388
pub(crate) nominal_sp_offset: u32,
1389
1390
/// Offset from the actual SP to the SP during an outgoing function call.
1391
/// This is normally always zero, except during processing of the return
1392
/// argument handling after a call using the tail-call ABI has returned.
1393
pub(crate) outgoing_sp_offset: u32,
1394
1395
/// Size of the incoming argument area in the caller's frame. Always zero
1396
/// for functions using the tail-call ABI.
1397
pub(crate) incoming_args_size: u32,
1398
1399
/// The user stack map for the upcoming instruction, as provided to
1400
/// `pre_safepoint()`.
1401
user_stack_map: Option<ir::UserStackMap>,
1402
1403
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
1404
/// optimized away at compiletime. See [cranelift_control].
1405
ctrl_plane: ControlPlane,
1406
1407
frame_layout: FrameLayout,
1408
}
1409
1410
impl MachInstEmitState<Inst> for EmitState {
1411
fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {
1412
let incoming_args_size = if abi.call_conv() == CallConv::Tail {
1413
0
1414
} else {
1415
abi.frame_layout().incoming_args_size
1416
};
1417
EmitState {
1418
nominal_sp_offset: 0,
1419
outgoing_sp_offset: 0,
1420
incoming_args_size,
1421
user_stack_map: None,
1422
ctrl_plane,
1423
frame_layout: abi.frame_layout().clone(),
1424
}
1425
}
1426
1427
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
1428
self.user_stack_map = user_stack_map;
1429
}
1430
1431
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
1432
&mut self.ctrl_plane
1433
}
1434
1435
fn take_ctrl_plane(self) -> ControlPlane {
1436
self.ctrl_plane
1437
}
1438
1439
fn frame_layout(&self) -> &FrameLayout {
1440
&self.frame_layout
1441
}
1442
}
1443
1444
impl EmitState {
1445
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
1446
self.user_stack_map.take()
1447
}
1448
1449
fn clear_post_insn(&mut self) {
1450
self.user_stack_map = None;
1451
}
1452
}
1453
1454
/// Constant state used during function compilation.
1455
pub struct EmitInfo {
1456
isa_flags: s390x_settings::Flags,
1457
}
1458
1459
impl EmitInfo {
1460
pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self {
1461
Self { isa_flags }
1462
}
1463
}
1464
1465
impl MachInstEmit for Inst {
1466
type State = EmitState;
1467
type Info = EmitInfo;
1468
1469
fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
1470
self.emit_with_alloc_consumer(sink, emit_info, state)
1471
}
1472
1473
fn pretty_print_inst(&self, state: &mut EmitState) -> String {
1474
self.print_with_state(state)
1475
}
1476
}
1477
1478
impl Inst {
1479
fn emit_with_alloc_consumer(
1480
&self,
1481
sink: &mut MachBuffer<Inst>,
1482
emit_info: &EmitInfo,
1483
state: &mut EmitState,
1484
) {
1485
// Verify that we can emit this Inst in the current ISA
1486
let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {
1487
match iset_requirement {
1488
// Baseline ISA is z14
1489
InstructionSet::Base => true,
1490
// Miscellaneous-Instruction-Extensions Facility 3 (z15)
1491
InstructionSet::MIE3 => emit_info.isa_flags.has_mie3(),
1492
// Miscellaneous-Instruction-Extensions Facility 4 (z17)
1493
InstructionSet::MIE4 => emit_info.isa_flags.has_mie4(),
1494
// Vector-Enhancements Facility 2 (z15)
1495
InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),
1496
// Vector-Enhancements Facility 3 (z17)
1497
InstructionSet::VXRS_EXT3 => emit_info.isa_flags.has_vxrs_ext3(),
1498
}
1499
};
1500
let isa_requirements = self.available_in_isa();
1501
if !matches_isa_flags(&isa_requirements) {
1502
panic!(
1503
"Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}"
1504
)
1505
}
1506
1507
match self {
1508
&Inst::AluRRR { alu_op, rd, rn, rm } => {
1509
let (opcode, have_rr) = match alu_op {
1510
ALUOp::Add32 => (0xb9f8, true), // ARK
1511
ALUOp::Add64 => (0xb9e8, true), // AGRK
1512
ALUOp::AddLogical32 => (0xb9fa, true), // ALRK
1513
ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK
1514
ALUOp::Sub32 => (0xb9f9, true), // SRK
1515
ALUOp::Sub64 => (0xb9e9, true), // SGRK
1516
ALUOp::SubLogical32 => (0xb9fb, true), // SLRK
1517
ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK
1518
ALUOp::Mul32 => (0xb9fd, true), // MSRKC
1519
ALUOp::Mul64 => (0xb9ed, true), // MSGRKC
1520
ALUOp::And32 => (0xb9f4, true), // NRK
1521
ALUOp::And64 => (0xb9e4, true), // NGRK
1522
ALUOp::Orr32 => (0xb9f6, true), // ORK
1523
ALUOp::Orr64 => (0xb9e6, true), // OGRK
1524
ALUOp::Xor32 => (0xb9f7, true), // XRK
1525
ALUOp::Xor64 => (0xb9e7, true), // XGRK
1526
ALUOp::NotAnd32 => (0xb974, false), // NNRK
1527
ALUOp::NotAnd64 => (0xb964, false), // NNGRK
1528
ALUOp::NotOrr32 => (0xb976, false), // NORK
1529
ALUOp::NotOrr64 => (0xb966, false), // NOGRK
1530
ALUOp::NotXor32 => (0xb977, false), // NXRK
1531
ALUOp::NotXor64 => (0xb967, false), // NXGRK
1532
ALUOp::AndNot32 => (0xb9f5, false), // NCRK
1533
ALUOp::AndNot64 => (0xb9e5, false), // NCGRK
1534
ALUOp::OrrNot32 => (0xb975, false), // OCRK
1535
ALUOp::OrrNot64 => (0xb965, false), // OCGRK
1536
_ => unreachable!(),
1537
};
1538
if have_rr && rd.to_reg() == rn {
1539
let inst = Inst::AluRR {
1540
alu_op,
1541
rd,
1542
ri: rn,
1543
rm,
1544
};
1545
inst.emit(sink, emit_info, state);
1546
} else {
1547
put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0));
1548
}
1549
}
1550
&Inst::AluRRSImm16 {
1551
alu_op,
1552
rd,
1553
rn,
1554
imm,
1555
} => {
1556
if rd.to_reg() == rn {
1557
let inst = Inst::AluRSImm16 {
1558
alu_op,
1559
rd,
1560
ri: rn,
1561
imm,
1562
};
1563
inst.emit(sink, emit_info, state);
1564
} else {
1565
let opcode = match alu_op {
1566
ALUOp::Add32 => 0xecd8, // AHIK
1567
ALUOp::Add64 => 0xecd9, // AGHIK
1568
_ => unreachable!(),
1569
};
1570
put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16));
1571
}
1572
}
1573
&Inst::AluRR { alu_op, rd, ri, rm } => {
1574
debug_assert_eq!(rd.to_reg(), ri);
1575
1576
let (opcode, is_rre) = match alu_op {
1577
ALUOp::Add32 => (0x1a, false), // AR
1578
ALUOp::Add64 => (0xb908, true), // AGR
1579
ALUOp::Add64Ext32 => (0xb918, true), // AGFR
1580
ALUOp::AddLogical32 => (0x1e, false), // ALR
1581
ALUOp::AddLogical64 => (0xb90a, true), // ALGR
1582
ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR
1583
ALUOp::Sub32 => (0x1b, false), // SR
1584
ALUOp::Sub64 => (0xb909, true), // SGR
1585
ALUOp::Sub64Ext32 => (0xb919, true), // SGFR
1586
ALUOp::SubLogical32 => (0x1f, false), // SLR
1587
ALUOp::SubLogical64 => (0xb90b, true), // SLGR
1588
ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR
1589
ALUOp::Mul32 => (0xb252, true), // MSR
1590
ALUOp::Mul64 => (0xb90c, true), // MSGR
1591
ALUOp::Mul64Ext32 => (0xb91c, true), // MSGFR
1592
ALUOp::And32 => (0x14, false), // NR
1593
ALUOp::And64 => (0xb980, true), // NGR
1594
ALUOp::Orr32 => (0x16, false), // OR
1595
ALUOp::Orr64 => (0xb981, true), // OGR
1596
ALUOp::Xor32 => (0x17, false), // XR
1597
ALUOp::Xor64 => (0xb982, true), // XGR
1598
_ => unreachable!(),
1599
};
1600
if is_rre {
1601
put(sink, &enc_rre(opcode, rd.to_reg(), rm));
1602
} else {
1603
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
1604
}
1605
}
1606
&Inst::AluRX {
1607
alu_op,
1608
rd,
1609
ri,
1610
ref mem,
1611
} => {
1612
debug_assert_eq!(rd.to_reg(), ri);
1613
let mem = mem.clone();
1614
1615
let (opcode_rx, opcode_rxy) = match alu_op {
1616
ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), // A(Y)
1617
ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), // AH(Y)
1618
ALUOp::Add64 => (None, Some(0xe308)), // AG
1619
ALUOp::Add64Ext16 => (None, Some(0xe338)), // AGH
1620
ALUOp::Add64Ext32 => (None, Some(0xe318)), // AGF
1621
ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y)
1622
ALUOp::AddLogical64 => (None, Some(0xe30a)), // ALG
1623
ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), // ALGF
1624
ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), // S(Y)
1625
ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), // SH(Y)
1626
ALUOp::Sub64 => (None, Some(0xe309)), // SG
1627
ALUOp::Sub64Ext16 => (None, Some(0xe339)), // SGH
1628
ALUOp::Sub64Ext32 => (None, Some(0xe319)), // SGF
1629
ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y)
1630
ALUOp::SubLogical64 => (None, Some(0xe30b)), // SLG
1631
ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), // SLGF
1632
ALUOp::Mul32 => (Some(0x71), Some(0xe351)), // MS(Y)
1633
ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), // MH(Y)
1634
ALUOp::Mul64 => (None, Some(0xe30c)), // MSG
1635
ALUOp::Mul64Ext16 => (None, Some(0xe33c)), // MSH
1636
ALUOp::Mul64Ext32 => (None, Some(0xe31c)), // MSGF
1637
ALUOp::And32 => (Some(0x54), Some(0xe354)), // N(Y)
1638
ALUOp::And64 => (None, Some(0xe380)), // NG
1639
ALUOp::Orr32 => (Some(0x56), Some(0xe356)), // O(Y)
1640
ALUOp::Orr64 => (None, Some(0xe381)), // OG
1641
ALUOp::Xor32 => (Some(0x57), Some(0xe357)), // X(Y)
1642
ALUOp::Xor64 => (None, Some(0xe382)), // XG
1643
_ => unreachable!(),
1644
};
1645
let rd = rd.to_reg();
1646
mem_emit(
1647
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
1648
);
1649
}
1650
&Inst::AluRSImm16 {
1651
alu_op,
1652
rd,
1653
ri,
1654
imm,
1655
} => {
1656
debug_assert_eq!(rd.to_reg(), ri);
1657
1658
let opcode = match alu_op {
1659
ALUOp::Add32 => 0xa7a, // AHI
1660
ALUOp::Add64 => 0xa7b, // AGHI
1661
ALUOp::Mul32 => 0xa7c, // MHI
1662
ALUOp::Mul64 => 0xa7d, // MGHI
1663
_ => unreachable!(),
1664
};
1665
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
1666
}
1667
&Inst::AluRSImm32 {
1668
alu_op,
1669
rd,
1670
ri,
1671
imm,
1672
} => {
1673
debug_assert_eq!(rd.to_reg(), ri);
1674
1675
let opcode = match alu_op {
1676
ALUOp::Add32 => 0xc29, // AFI
1677
ALUOp::Add64 => 0xc28, // AGFI
1678
ALUOp::Mul32 => 0xc21, // MSFI
1679
ALUOp::Mul64 => 0xc20, // MSGFI
1680
_ => unreachable!(),
1681
};
1682
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
1683
}
1684
&Inst::AluRUImm32 {
1685
alu_op,
1686
rd,
1687
ri,
1688
imm,
1689
} => {
1690
debug_assert_eq!(rd.to_reg(), ri);
1691
1692
let opcode = match alu_op {
1693
ALUOp::AddLogical32 => 0xc2b, // ALFI
1694
ALUOp::AddLogical64 => 0xc2a, // ALGFI
1695
ALUOp::SubLogical32 => 0xc25, // SLFI
1696
ALUOp::SubLogical64 => 0xc24, // SLGFI
1697
_ => unreachable!(),
1698
};
1699
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
1700
}
1701
&Inst::AluRUImm16Shifted {
1702
alu_op,
1703
rd,
1704
ri,
1705
imm,
1706
} => {
1707
debug_assert_eq!(rd.to_reg(), ri);
1708
1709
let opcode = match (alu_op, imm.shift) {
1710
(ALUOp::And32, 0) => 0xa57, // NILL
1711
(ALUOp::And32, 1) => 0xa56, // NILH
1712
(ALUOp::And64, 0) => 0xa57, // NILL
1713
(ALUOp::And64, 1) => 0xa56, // NILH
1714
(ALUOp::And64, 2) => 0xa55, // NIHL
1715
(ALUOp::And64, 3) => 0xa54, // NIHL
1716
(ALUOp::Orr32, 0) => 0xa5b, // OILL
1717
(ALUOp::Orr32, 1) => 0xa5a, // OILH
1718
(ALUOp::Orr64, 0) => 0xa5b, // OILL
1719
(ALUOp::Orr64, 1) => 0xa5a, // OILH
1720
(ALUOp::Orr64, 2) => 0xa59, // OIHL
1721
(ALUOp::Orr64, 3) => 0xa58, // OIHH
1722
_ => unreachable!(),
1723
};
1724
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
1725
}
1726
&Inst::AluRUImm32Shifted {
1727
alu_op,
1728
rd,
1729
ri,
1730
imm,
1731
} => {
1732
debug_assert_eq!(rd.to_reg(), ri);
1733
1734
let opcode = match (alu_op, imm.shift) {
1735
(ALUOp::And32, 0) => 0xc0b, // NILF
1736
(ALUOp::And64, 0) => 0xc0b, // NILF
1737
(ALUOp::And64, 1) => 0xc0a, // NIHF
1738
(ALUOp::Orr32, 0) => 0xc0d, // OILF
1739
(ALUOp::Orr64, 0) => 0xc0d, // OILF
1740
(ALUOp::Orr64, 1) => 0xc0c, // OILF
1741
(ALUOp::Xor32, 0) => 0xc07, // XILF
1742
(ALUOp::Xor64, 0) => 0xc07, // XILF
1743
(ALUOp::Xor64, 1) => 0xc06, // XILH
1744
_ => unreachable!(),
1745
};
1746
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
1747
}
1748
1749
&Inst::SMulWide { rd, rn, rm } => {
1750
let rd1 = rd.hi;
1751
let rd2 = rd.lo;
1752
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1753
1754
let opcode = 0xb9ec; // MGRK
1755
put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0));
1756
}
1757
&Inst::UMulWide { rd, ri, rn } => {
1758
let rd1 = rd.hi;
1759
let rd2 = rd.lo;
1760
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1761
debug_assert_eq!(rd2.to_reg(), ri);
1762
1763
let opcode = 0xb986; // MLGR
1764
put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1765
}
1766
&Inst::SDivMod32 { rd, ri, rn } => {
1767
let rd1 = rd.hi;
1768
let rd2 = rd.lo;
1769
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1770
debug_assert_eq!(rd2.to_reg(), ri);
1771
1772
let opcode = 0xb91d; // DSGFR
1773
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1774
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1775
}
1776
&Inst::SDivMod64 { rd, ri, rn } => {
1777
let rd1 = rd.hi;
1778
let rd2 = rd.lo;
1779
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1780
debug_assert_eq!(rd2.to_reg(), ri);
1781
1782
let opcode = 0xb90d; // DSGR
1783
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1784
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1785
}
1786
&Inst::UDivMod32 { rd, ri, rn } => {
1787
let rd1 = rd.hi;
1788
let rd2 = rd.lo;
1789
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1790
let ri1 = ri.hi;
1791
let ri2 = ri.lo;
1792
debug_assert_eq!(rd1.to_reg(), ri1);
1793
debug_assert_eq!(rd2.to_reg(), ri2);
1794
1795
let opcode = 0xb997; // DLR
1796
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1797
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1798
}
1799
&Inst::UDivMod64 { rd, ri, rn } => {
1800
let rd1 = rd.hi;
1801
let rd2 = rd.lo;
1802
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1803
let ri1 = ri.hi;
1804
let ri2 = ri.lo;
1805
debug_assert_eq!(rd1.to_reg(), ri1);
1806
debug_assert_eq!(rd2.to_reg(), ri2);
1807
1808
let opcode = 0xb987; // DLGR
1809
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1810
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1811
}
1812
&Inst::Flogr { rd, rn } => {
1813
let rd1 = rd.hi;
1814
let rd2 = rd.lo;
1815
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1816
1817
let opcode = 0xb983; // FLOGR
1818
put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1819
}
1820
1821
&Inst::ShiftRR {
1822
shift_op,
1823
rd,
1824
rn,
1825
shift_imm,
1826
shift_reg,
1827
} => {
1828
let opcode = match shift_op {
1829
ShiftOp::RotL32 => 0xeb1d, // RLL
1830
ShiftOp::RotL64 => 0xeb1c, // RLLG
1831
ShiftOp::LShL32 => 0xebdf, // SLLK (SLL ?)
1832
ShiftOp::LShL64 => 0xeb0d, // SLLG
1833
ShiftOp::LShR32 => 0xebde, // SRLK (SRL ?)
1834
ShiftOp::LShR64 => 0xeb0c, // SRLG
1835
ShiftOp::AShR32 => 0xebdc, // SRAK (SRA ?)
1836
ShiftOp::AShR64 => 0xeb0a, // SRAG
1837
};
1838
put(
1839
sink,
1840
&enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()),
1841
);
1842
}
1843
1844
&Inst::RxSBG {
1845
op,
1846
rd,
1847
ri,
1848
rn,
1849
start_bit,
1850
end_bit,
1851
rotate_amt,
1852
} => {
1853
debug_assert_eq!(rd.to_reg(), ri);
1854
1855
let opcode = match op {
1856
RxSBGOp::Insert => 0xec59, // RISBGN
1857
RxSBGOp::And => 0xec54, // RNSBG
1858
RxSBGOp::Or => 0xec56, // ROSBG
1859
RxSBGOp::Xor => 0xec57, // RXSBG
1860
};
1861
put(
1862
sink,
1863
&enc_rie_f(
1864
opcode,
1865
rd.to_reg(),
1866
rn,
1867
start_bit,
1868
end_bit,
1869
(rotate_amt as u8) & 63,
1870
),
1871
);
1872
}
1873
1874
&Inst::RxSBGTest {
1875
op,
1876
rd,
1877
rn,
1878
start_bit,
1879
end_bit,
1880
rotate_amt,
1881
} => {
1882
let opcode = match op {
1883
RxSBGOp::And => 0xec54, // RNSBG
1884
RxSBGOp::Or => 0xec56, // ROSBG
1885
RxSBGOp::Xor => 0xec57, // RXSBG
1886
_ => unreachable!(),
1887
};
1888
put(
1889
sink,
1890
&enc_rie_f(
1891
opcode,
1892
rd,
1893
rn,
1894
start_bit | 0x80,
1895
end_bit,
1896
(rotate_amt as u8) & 63,
1897
),
1898
);
1899
}
1900
1901
&Inst::UnaryRR { op, rd, rn } => {
1902
match op {
1903
UnaryOp::Abs32 => {
1904
let opcode = 0x10; // LPR
1905
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1906
}
1907
UnaryOp::Abs64 => {
1908
let opcode = 0xb900; // LPGR
1909
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1910
}
1911
UnaryOp::Abs64Ext32 => {
1912
let opcode = 0xb910; // LPGFR
1913
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1914
}
1915
UnaryOp::Neg32 => {
1916
let opcode = 0x13; // LCR
1917
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1918
}
1919
UnaryOp::Neg64 => {
1920
let opcode = 0xb903; // LCGR
1921
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1922
}
1923
UnaryOp::Neg64Ext32 => {
1924
let opcode = 0xb913; // LCGFR
1925
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1926
}
1927
UnaryOp::PopcntByte => {
1928
let opcode = 0xb9e1; // POPCNT
1929
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));
1930
}
1931
UnaryOp::PopcntReg => {
1932
let opcode = 0xb9e1; // POPCNT
1933
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));
1934
}
1935
UnaryOp::BSwap32 => {
1936
let opcode = 0xb91f; // LRVR
1937
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1938
}
1939
UnaryOp::BSwap64 => {
1940
let opcode = 0xb90f; // LRVRG
1941
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1942
}
1943
UnaryOp::Clz64 => {
1944
let opcode = 0xb968; // CLZG
1945
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1946
}
1947
UnaryOp::Ctz64 => {
1948
let opcode = 0xb969; // CTZG
1949
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1950
}
1951
}
1952
}
1953
1954
&Inst::Extend {
1955
rd,
1956
rn,
1957
signed,
1958
from_bits,
1959
to_bits,
1960
} => {
1961
let opcode = match (signed, from_bits, to_bits) {
1962
(_, 1, 32) => 0xb926, // LBR
1963
(_, 1, 64) => 0xb906, // LGBR
1964
(false, 8, 32) => 0xb994, // LLCR
1965
(false, 8, 64) => 0xb984, // LLGCR
1966
(true, 8, 32) => 0xb926, // LBR
1967
(true, 8, 64) => 0xb906, // LGBR
1968
(false, 16, 32) => 0xb995, // LLHR
1969
(false, 16, 64) => 0xb985, // LLGHR
1970
(true, 16, 32) => 0xb927, // LHR
1971
(true, 16, 64) => 0xb907, // LGHR
1972
(false, 32, 64) => 0xb916, // LLGFR
1973
(true, 32, 64) => 0xb914, // LGFR
1974
_ => panic!(
1975
"Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}"
1976
),
1977
};
1978
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1979
}
1980
1981
&Inst::CmpRR { op, rn, rm } => {
1982
let (opcode, is_rre) = match op {
1983
CmpOp::CmpS32 => (0x19, false), // CR
1984
CmpOp::CmpS64 => (0xb920, true), // CGR
1985
CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR
1986
CmpOp::CmpL32 => (0x15, false), // CLR
1987
CmpOp::CmpL64 => (0xb921, true), // CLGR
1988
CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR
1989
_ => unreachable!(),
1990
};
1991
if is_rre {
1992
put(sink, &enc_rre(opcode, rn, rm));
1993
} else {
1994
put(sink, &enc_rr(opcode, rn, rm));
1995
}
1996
}
1997
&Inst::CmpRX { op, rn, ref mem } => {
1998
let mem = mem.clone();
1999
2000
let (opcode_rx, opcode_rxy, opcode_ril) = match op {
2001
CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), // C(Y), CRL
2002
CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL
2003
CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), // CG, CGRL
2004
CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), // CGH, CGHRL
2005
CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), // CGF, CGFRL
2006
CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL
2007
CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), // CLHRL
2008
CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), // CLG, CLGRL
2009
CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), // CLGHRL
2010
CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), // CLGF, CLGFRL
2011
};
2012
mem_emit(
2013
rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2014
);
2015
}
2016
&Inst::CmpRSImm16 { op, rn, imm } => {
2017
let opcode = match op {
2018
CmpOp::CmpS32 => 0xa7e, // CHI
2019
CmpOp::CmpS64 => 0xa7f, // CGHI
2020
_ => unreachable!(),
2021
};
2022
put(sink, &enc_ri_a(opcode, rn, imm as u16));
2023
}
2024
&Inst::CmpRSImm32 { op, rn, imm } => {
2025
let opcode = match op {
2026
CmpOp::CmpS32 => 0xc2d, // CFI
2027
CmpOp::CmpS64 => 0xc2c, // CGFI
2028
_ => unreachable!(),
2029
};
2030
put(sink, &enc_ril_a(opcode, rn, imm as u32));
2031
}
2032
&Inst::CmpRUImm32 { op, rn, imm } => {
2033
let opcode = match op {
2034
CmpOp::CmpL32 => 0xc2f, // CLFI
2035
CmpOp::CmpL64 => 0xc2e, // CLGFI
2036
_ => unreachable!(),
2037
};
2038
put(sink, &enc_ril_a(opcode, rn, imm));
2039
}
2040
&Inst::CmpTrapRR {
2041
op,
2042
rn,
2043
rm,
2044
cond,
2045
trap_code,
2046
} => {
2047
let opcode = match op {
2048
CmpOp::CmpS32 => 0xb972, // CRT
2049
CmpOp::CmpS64 => 0xb960, // CGRT
2050
CmpOp::CmpL32 => 0xb973, // CLRT
2051
CmpOp::CmpL64 => 0xb961, // CLGRT
2052
_ => unreachable!(),
2053
};
2054
put_with_trap(
2055
sink,
2056
&enc_rrf_cde(opcode, rn, rm, cond.bits(), 0),
2057
trap_code,
2058
);
2059
}
2060
&Inst::CmpTrapRSImm16 {
2061
op,
2062
rn,
2063
imm,
2064
cond,
2065
trap_code,
2066
} => {
2067
let opcode = match op {
2068
CmpOp::CmpS32 => 0xec72, // CIT
2069
CmpOp::CmpS64 => 0xec70, // CGIT
2070
_ => unreachable!(),
2071
};
2072
put_with_trap(
2073
sink,
2074
&enc_rie_a(opcode, rn, imm as u16, cond.bits()),
2075
trap_code,
2076
);
2077
}
2078
&Inst::CmpTrapRUImm16 {
2079
op,
2080
rn,
2081
imm,
2082
cond,
2083
trap_code,
2084
} => {
2085
let opcode = match op {
2086
CmpOp::CmpL32 => 0xec73, // CLFIT
2087
CmpOp::CmpL64 => 0xec71, // CLGIT
2088
_ => unreachable!(),
2089
};
2090
put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code);
2091
}
2092
2093
&Inst::AtomicRmw {
2094
alu_op,
2095
rd,
2096
rn,
2097
ref mem,
2098
} => {
2099
let mem = mem.clone();
2100
2101
let opcode = match alu_op {
2102
ALUOp::Add32 => 0xebf8, // LAA
2103
ALUOp::Add64 => 0xebe8, // LAAG
2104
ALUOp::AddLogical32 => 0xebfa, // LAAL
2105
ALUOp::AddLogical64 => 0xebea, // LAALG
2106
ALUOp::And32 => 0xebf4, // LAN
2107
ALUOp::And64 => 0xebe4, // LANG
2108
ALUOp::Orr32 => 0xebf6, // LAO
2109
ALUOp::Orr64 => 0xebe6, // LAOG
2110
ALUOp::Xor32 => 0xebf7, // LAX
2111
ALUOp::Xor64 => 0xebe7, // LAXG
2112
_ => unreachable!(),
2113
};
2114
2115
let rd = rd.to_reg();
2116
mem_rs_emit(
2117
rd,
2118
rn,
2119
&mem,
2120
None,
2121
Some(opcode),
2122
true,
2123
sink,
2124
emit_info,
2125
state,
2126
);
2127
}
2128
&Inst::Loop { ref body, cond } => {
2129
// This sequence is *one* instruction in the vcode, and is expanded only here at
2130
// emission time, because it requires branching to internal labels.
2131
let loop_label = sink.get_label();
2132
let done_label = sink.get_label();
2133
2134
// Emit label at the start of the loop.
2135
sink.bind_label(loop_label, &mut state.ctrl_plane);
2136
2137
for inst in (&body).into_iter() {
2138
match &inst {
2139
// Replace a CondBreak with a branch to done_label.
2140
&Inst::CondBreak { cond } => {
2141
let opcode = 0xc04; // BCRL
2142
sink.use_label_at_offset(
2143
sink.cur_offset(),
2144
done_label,
2145
LabelUse::BranchRIL,
2146
);
2147
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2148
}
2149
_ => inst.emit_with_alloc_consumer(sink, emit_info, state),
2150
};
2151
}
2152
2153
let opcode = 0xc04; // BCRL
2154
sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);
2155
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2156
2157
// Emit label at the end of the loop.
2158
sink.bind_label(done_label, &mut state.ctrl_plane);
2159
}
2160
&Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.
2161
&Inst::AtomicCas32 {
2162
rd,
2163
ri,
2164
rn,
2165
ref mem,
2166
}
2167
| &Inst::AtomicCas64 {
2168
rd,
2169
ri,
2170
rn,
2171
ref mem,
2172
} => {
2173
debug_assert_eq!(rd.to_reg(), ri);
2174
let mem = mem.clone();
2175
2176
let (opcode_rs, opcode_rsy) = match self {
2177
&Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), // CS(Y)
2178
&Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), // CSG
2179
_ => unreachable!(),
2180
};
2181
2182
let rd = rd.to_reg();
2183
mem_rs_emit(
2184
rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state,
2185
);
2186
}
2187
&Inst::Fence => {
2188
put(sink, &enc_e(0x07e0));
2189
}
2190
2191
&Inst::Load32 { rd, ref mem }
2192
| &Inst::Load32ZExt8 { rd, ref mem }
2193
| &Inst::Load32SExt8 { rd, ref mem }
2194
| &Inst::Load32ZExt16 { rd, ref mem }
2195
| &Inst::Load32SExt16 { rd, ref mem }
2196
| &Inst::Load64 { rd, ref mem }
2197
| &Inst::Load64ZExt8 { rd, ref mem }
2198
| &Inst::Load64SExt8 { rd, ref mem }
2199
| &Inst::Load64ZExt16 { rd, ref mem }
2200
| &Inst::Load64SExt16 { rd, ref mem }
2201
| &Inst::Load64ZExt32 { rd, ref mem }
2202
| &Inst::Load64SExt32 { rd, ref mem }
2203
| &Inst::LoadRev16 { rd, ref mem }
2204
| &Inst::LoadRev32 { rd, ref mem }
2205
| &Inst::LoadRev64 { rd, ref mem } => {
2206
let mem = mem.clone();
2207
2208
let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2209
&Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), // L(Y), LRL
2210
&Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), // LLC
2211
&Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), // LB
2212
&Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL
2213
&Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL
2214
&Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL
2215
&Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), // LLGC
2216
&Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), // LGB
2217
&Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL
2218
&Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL
2219
&Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL
2220
&Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL
2221
&Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), // LRVH
2222
&Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), // LRV
2223
&Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), // LRVG
2224
_ => unreachable!(),
2225
};
2226
let rd = rd.to_reg();
2227
mem_emit(
2228
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2229
);
2230
}
2231
2232
&Inst::Store8 { rd, ref mem }
2233
| &Inst::Store16 { rd, ref mem }
2234
| &Inst::Store32 { rd, ref mem }
2235
| &Inst::Store64 { rd, ref mem }
2236
| &Inst::StoreRev16 { rd, ref mem }
2237
| &Inst::StoreRev32 { rd, ref mem }
2238
| &Inst::StoreRev64 { rd, ref mem } => {
2239
let mem = mem.clone();
2240
2241
let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2242
&Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), // STC(Y)
2243
&Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL
2244
&Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL
2245
&Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), // STG, STGRL
2246
&Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), // STRVH
2247
&Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), // STRV
2248
&Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), // STRVG
2249
_ => unreachable!(),
2250
};
2251
mem_emit(
2252
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2253
);
2254
}
2255
&Inst::StoreImm8 { imm, ref mem } => {
2256
let mem = mem.clone();
2257
2258
let opcode_si = 0x92; // MVI
2259
let opcode_siy = 0xeb52; // MVIY
2260
mem_imm8_emit(
2261
imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state,
2262
);
2263
}
2264
&Inst::StoreImm16 { imm, ref mem }
2265
| &Inst::StoreImm32SExt16 { imm, ref mem }
2266
| &Inst::StoreImm64SExt16 { imm, ref mem } => {
2267
let mem = mem.clone();
2268
2269
let opcode = match self {
2270
&Inst::StoreImm16 { .. } => 0xe544, // MVHHI
2271
&Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI
2272
&Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI
2273
_ => unreachable!(),
2274
};
2275
mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);
2276
}
2277
2278
&Inst::LoadMultiple64 { rt, rt2, ref mem } => {
2279
let mem = mem.clone();
2280
2281
let opcode = 0xeb04; // LMG
2282
let rt = rt.to_reg();
2283
let rt2 = rt2.to_reg();
2284
mem_rs_emit(
2285
rt,
2286
rt2,
2287
&mem,
2288
None,
2289
Some(opcode),
2290
true,
2291
sink,
2292
emit_info,
2293
state,
2294
);
2295
}
2296
&Inst::StoreMultiple64 { rt, rt2, ref mem } => {
2297
let mem = mem.clone();
2298
2299
let opcode = 0xeb24; // STMG
2300
mem_rs_emit(
2301
rt,
2302
rt2,
2303
&mem,
2304
None,
2305
Some(opcode),
2306
true,
2307
sink,
2308
emit_info,
2309
state,
2310
);
2311
}
2312
2313
&Inst::LoadAddr { rd, ref mem } => {
2314
let mem = mem.clone();
2315
2316
let opcode_rx = Some(0x41); // LA
2317
let opcode_rxy = Some(0xe371); // LAY
2318
let opcode_ril = Some(0xc00); // LARL
2319
let rd = rd.to_reg();
2320
mem_emit(
2321
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,
2322
);
2323
}
2324
2325
&Inst::Mov64 { rd, rm } => {
2326
let opcode = 0xb904; // LGR
2327
put(sink, &enc_rre(opcode, rd.to_reg(), rm));
2328
}
2329
&Inst::MovPReg { rd, rm } => {
2330
Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);
2331
}
2332
&Inst::Mov32 { rd, rm } => {
2333
let opcode = 0x18; // LR
2334
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2335
}
2336
&Inst::Mov32Imm { rd, imm } => {
2337
let opcode = 0xc09; // IILF
2338
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
2339
}
2340
&Inst::Mov32SImm16 { rd, imm } => {
2341
let opcode = 0xa78; // LHI
2342
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2343
}
2344
&Inst::Mov64SImm16 { rd, imm } => {
2345
let opcode = 0xa79; // LGHI
2346
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2347
}
2348
&Inst::Mov64SImm32 { rd, imm } => {
2349
let opcode = 0xc01; // LGFI
2350
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
2351
}
2352
&Inst::CMov32 { rd, cond, ri, rm } => {
2353
debug_assert_eq!(rd.to_reg(), ri);
2354
2355
let opcode = 0xb9f2; // LOCR
2356
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2357
}
2358
&Inst::CMov64 { rd, cond, ri, rm } => {
2359
debug_assert_eq!(rd.to_reg(), ri);
2360
2361
let opcode = 0xb9e2; // LOCGR
2362
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2363
}
2364
&Inst::CMov32SImm16 { rd, cond, ri, imm } => {
2365
debug_assert_eq!(rd.to_reg(), ri);
2366
2367
let opcode = 0xec42; // LOCHI
2368
put(
2369
sink,
2370
&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2371
);
2372
}
2373
&Inst::CMov64SImm16 { rd, cond, ri, imm } => {
2374
debug_assert_eq!(rd.to_reg(), ri);
2375
2376
let opcode = 0xec46; // LOCGHI
2377
put(
2378
sink,
2379
&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2380
);
2381
}
2382
&Inst::Mov64UImm16Shifted { rd, imm } => {
2383
let opcode = match imm.shift {
2384
0 => 0xa5f, // LLILL
2385
1 => 0xa5e, // LLILH
2386
2 => 0xa5d, // LLIHL
2387
3 => 0xa5c, // LLIHH
2388
_ => unreachable!(),
2389
};
2390
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2391
}
2392
&Inst::Mov64UImm32Shifted { rd, imm } => {
2393
let opcode = match imm.shift {
2394
0 => 0xc0f, // LLILF
2395
1 => 0xc0e, // LLIHF
2396
_ => unreachable!(),
2397
};
2398
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2399
}
2400
&Inst::Insert64UImm16Shifted { rd, ri, imm } => {
2401
debug_assert_eq!(rd.to_reg(), ri);
2402
2403
let opcode = match imm.shift {
2404
0 => 0xa53, // IILL
2405
1 => 0xa52, // IILH
2406
2 => 0xa51, // IIHL
2407
3 => 0xa50, // IIHH
2408
_ => unreachable!(),
2409
};
2410
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2411
}
2412
&Inst::Insert64UImm32Shifted { rd, ri, imm } => {
2413
debug_assert_eq!(rd.to_reg(), ri);
2414
2415
let opcode = match imm.shift {
2416
0 => 0xc09, // IILF
2417
1 => 0xc08, // IIHF
2418
_ => unreachable!(),
2419
};
2420
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2421
}
2422
&Inst::LoadAR { rd, ar } => {
2423
let opcode = 0xb24f; // EAR
2424
put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2425
}
2426
2427
&Inst::InsertAR { rd, ri, ar } => {
2428
debug_assert_eq!(rd.to_reg(), ri);
2429
2430
let opcode = 0xb24f; // EAR
2431
put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2432
}
2433
&Inst::LoadSymbolReloc {
2434
rd,
2435
ref symbol_reloc,
2436
} => {
2437
let reg = writable_spilltmp_reg().to_reg();
2438
put(sink, &enc_ri_b(OPCODE_BRAS, reg, 12));
2439
let (reloc, name, offset) = match &**symbol_reloc {
2440
SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset),
2441
SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0),
2442
};
2443
sink.add_reloc(reloc, name, offset);
2444
sink.put8(0);
2445
let inst = Inst::Load64 {
2446
rd,
2447
mem: MemArg::reg(reg, MemFlags::trusted()),
2448
};
2449
inst.emit(sink, emit_info, state);
2450
}
2451
2452
&Inst::FpuMove32 { rd, rn } => {
2453
if is_fpr(rd.to_reg()) && is_fpr(rn) {
2454
let opcode = 0x38; // LER
2455
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2456
} else {
2457
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
2458
}
2459
}
2460
&Inst::FpuMove64 { rd, rn } => {
2461
if is_fpr(rd.to_reg()) && is_fpr(rn) {
2462
put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rn));
2463
} else {
2464
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
2465
}
2466
}
2467
&Inst::FpuCMov32 { rd, cond, ri, rm } => {
2468
debug_assert_eq!(rd.to_reg(), ri);
2469
2470
if is_fpr(rd.to_reg()) && is_fpr(rm) {
2471
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));
2472
let opcode = 0x38; // LER
2473
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2474
} else {
2475
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
2476
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
2477
}
2478
}
2479
&Inst::FpuCMov64 { rd, cond, ri, rm } => {
2480
debug_assert_eq!(rd.to_reg(), ri);
2481
2482
if is_fpr(rd.to_reg()) && is_fpr(rm) {
2483
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));
2484
put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rm));
2485
} else {
2486
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
2487
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
2488
}
2489
}
2490
&Inst::FpuRR { fpu_op, rd, rn } => {
2491
let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op {
2492
FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), // WFPSO, LPEBR
2493
FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR
2494
FPUOp1::Abs128 => (0xe7cc, 4, 8, 2, None), // WFPSO
2495
FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), // VFPSO
2496
FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), // VFPSO
2497
FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR
2498
FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR
2499
FPUOp1::Neg128 => (0xe7cc, 4, 8, 0, None), // WFPSO
2500
FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), // VFPSO
2501
FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), // VFPSO
2502
FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR
2503
FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR
2504
FPUOp1::NegAbs128 => (0xe7cc, 4, 8, 1, None), // WFPSO
2505
FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), // VFPSO
2506
FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), // VFPSO
2507
FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR
2508
FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR
2509
FPUOp1::Sqrt128 => (0xe7ce, 4, 8, 0, None), // WFSQ
2510
FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), // VFSQ
2511
FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), // VFSQ
2512
FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR
2513
FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL
2514
FPUOp1::Cvt64To128 => (0xe7c4, 3, 8, 0, None), // WFLL
2515
};
2516
if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {
2517
put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn));
2518
} else {
2519
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5));
2520
}
2521
}
2522
&Inst::FpuRRR { fpu_op, rd, rn, rm } => {
2523
let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op {
2524
FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), // WFA, AEBR
2525
FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR
2526
FPUOp2::Add128 => (0xe7e3, 4, 8, 0, None), // WFA
2527
FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), // VFA
2528
FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), // VFA
2529
FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR
2530
FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR
2531
FPUOp2::Sub128 => (0xe7e2, 4, 8, 0, None), // WFS
2532
FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), // VFS
2533
FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), // VFS
2534
FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR
2535
FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR
2536
FPUOp2::Mul128 => (0xe7e7, 4, 8, 0, None), // WFM
2537
FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), // VFM
2538
FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), // VFM
2539
FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR
2540
FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR
2541
FPUOp2::Div128 => (0xe7e5, 4, 8, 0, None), // WFD
2542
FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), // VFD
2543
FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), // VFD
2544
FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), // WFMAX
2545
FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), // WFMAX
2546
FPUOp2::Max128 => (0xe7ef, 4, 8, 1, None), // WFMAX
2547
FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), // VFMAX
2548
FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), // VFMAX
2549
FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), // WFMIN
2550
FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), // WFMIN
2551
FPUOp2::Min128 => (0xe7ee, 4, 8, 1, None), // WFMIN
2552
FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), // VFMIN
2553
FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), // VFMIN
2554
FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), // WFMAX
2555
FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), // WFMAX
2556
FPUOp2::MaxPseudo128 => (0xe7ef, 4, 8, 3, None), // WFMAX
2557
FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX
2558
FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX
2559
FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), // WFMIN
2560
FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), // WFMIN
2561
FPUOp2::MinPseudo128 => (0xe7ee, 4, 8, 3, None), // WFMIN
2562
FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN
2563
FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN
2564
};
2565
if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm)
2566
{
2567
put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm));
2568
} else {
2569
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6));
2570
}
2571
}
2572
&Inst::FpuRRRR {
2573
fpu_op,
2574
rd,
2575
rn,
2576
rm,
2577
ra,
2578
} => {
2579
let (opcode, m5, m6, opcode_fpr) = match fpu_op {
2580
FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), // WFMA, MAEBR
2581
FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR
2582
FPUOp3::MAdd128 => (0xe78f, 8, 4, None), // WFMA
2583
FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), // VFMA
2584
FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), // VFMA
2585
FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR
2586
FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR
2587
FPUOp3::MSub128 => (0xe78e, 8, 4, None), // WFMS
2588
FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), // VFMS
2589
FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), // VFMS
2590
};
2591
if m5 == 8
2592
&& opcode_fpr.is_some()
2593
&& rd.to_reg() == ra
2594
&& is_fpr(rn)
2595
&& is_fpr(rm)
2596
&& is_fpr(ra)
2597
{
2598
put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn));
2599
} else {
2600
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6));
2601
}
2602
}
2603
&Inst::FpuRound { op, mode, rd, rn } => {
2604
let mode = match mode {
2605
FpuRoundMode::Current => 0,
2606
FpuRoundMode::ToNearest => 1,
2607
FpuRoundMode::ShorterPrecision => 3,
2608
FpuRoundMode::ToNearestTiesToEven => 4,
2609
FpuRoundMode::ToZero => 5,
2610
FpuRoundMode::ToPosInfinity => 6,
2611
FpuRoundMode::ToNegInfinity => 7,
2612
};
2613
let (opcode, m3, m4, opcode_fpr) = match op {
2614
FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), // WFLR, LEDBR(A)
2615
FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), // VFLR
2616
FpuRoundOp::Cvt128To64 => (0xe7c5, 4, 8, None), // WFLR
2617
FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), // WFI, FIEBR
2618
FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), // WFI, FIDBR
2619
FpuRoundOp::Round128 => (0xe7c7, 4, 8, None), // WFI
2620
FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), // VFI
2621
FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), // VFI
2622
FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), // WCSFP
2623
FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), // WCSFP
2624
FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), // WCLFP
2625
FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), // WCLFP
2626
FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), // VCSFP
2627
FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), // VCSFP
2628
FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), // VCLFP
2629
FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), // VCLFP
2630
FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), // WCFPS
2631
FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), // WCFPS
2632
FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), // WCFPL
2633
FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), // WCFPL
2634
FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), // VCFPS
2635
FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), // VCFPS
2636
FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), // VCFPL
2637
FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), // VCFPL
2638
};
2639
if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {
2640
put(
2641
sink,
2642
&enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0),
2643
);
2644
} else {
2645
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode));
2646
}
2647
}
2648
&Inst::FpuConv128FromInt { op, mode, rd, rn } => {
2649
let rd1 = rd.hi;
2650
let rd2 = rd.lo;
2651
debug_assert_valid_fp_regpair!(rd1.to_reg(), rd2.to_reg());
2652
2653
let mode = match mode {
2654
FpuRoundMode::Current => 0,
2655
FpuRoundMode::ToNearest => 1,
2656
FpuRoundMode::ShorterPrecision => 3,
2657
FpuRoundMode::ToNearestTiesToEven => 4,
2658
FpuRoundMode::ToZero => 5,
2659
FpuRoundMode::ToPosInfinity => 6,
2660
FpuRoundMode::ToNegInfinity => 7,
2661
};
2662
let opcode = match op {
2663
FpuConv128Op::SInt32 => 0xb396, // CXFBRA
2664
FpuConv128Op::SInt64 => 0xb3a6, // CXGBRA
2665
FpuConv128Op::UInt32 => 0xb392, // CXLFBR
2666
FpuConv128Op::UInt64 => 0xb3a2, // CXLGBR
2667
};
2668
put(sink, &enc_rrf_cde(opcode, rd1.to_reg(), rn, mode, 0));
2669
}
2670
&Inst::FpuConv128ToInt { op, mode, rd, rn } => {
2671
let rn1 = rn.hi;
2672
let rn2 = rn.lo;
2673
debug_assert_valid_fp_regpair!(rn1, rn2);
2674
2675
let mode = match mode {
2676
FpuRoundMode::Current => 0,
2677
FpuRoundMode::ToNearest => 1,
2678
FpuRoundMode::ShorterPrecision => 3,
2679
FpuRoundMode::ToNearestTiesToEven => 4,
2680
FpuRoundMode::ToZero => 5,
2681
FpuRoundMode::ToPosInfinity => 6,
2682
FpuRoundMode::ToNegInfinity => 7,
2683
};
2684
let opcode = match op {
2685
FpuConv128Op::SInt32 => 0xb39a, // CFXBRA
2686
FpuConv128Op::SInt64 => 0xb3aa, // CGXBRA
2687
FpuConv128Op::UInt32 => 0xb39e, // CLFXBR
2688
FpuConv128Op::UInt64 => 0xb3ae, // CLGXBR
2689
};
2690
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn1, mode, 0));
2691
}
2692
&Inst::FpuCmp32 { rn, rm } => {
2693
if is_fpr(rn) && is_fpr(rm) {
2694
let opcode = 0xb309; // CEBR
2695
put(sink, &enc_rre(opcode, rn, rm));
2696
} else {
2697
let opcode = 0xe7cb; // WFC
2698
put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0));
2699
}
2700
}
2701
&Inst::FpuCmp64 { rn, rm } => {
2702
if is_fpr(rn) && is_fpr(rm) {
2703
let opcode = 0xb319; // CDBR
2704
put(sink, &enc_rre(opcode, rn, rm));
2705
} else {
2706
let opcode = 0xe7cb; // WFC
2707
put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0));
2708
}
2709
}
2710
&Inst::FpuCmp128 { rn, rm } => {
2711
let opcode = 0xe7cb; // WFC
2712
put(sink, &enc_vrr_a(opcode, rn, rm, 4, 0, 0));
2713
}
2714
2715
&Inst::VecRRR { op, rd, rn, rm } => {
2716
let (opcode, m4) = match op {
2717
VecBinaryOp::Add8x16 => (0xe7f3, 0), // VAB
2718
VecBinaryOp::Add16x8 => (0xe7f3, 1), // VAH
2719
VecBinaryOp::Add32x4 => (0xe7f3, 2), // VAF
2720
VecBinaryOp::Add64x2 => (0xe7f3, 3), // VAG
2721
VecBinaryOp::Add128 => (0xe7f3, 4), // VAQ
2722
VecBinaryOp::Sub8x16 => (0xe7f7, 0), // VSB
2723
VecBinaryOp::Sub16x8 => (0xe7f7, 1), // VSH
2724
VecBinaryOp::Sub32x4 => (0xe7f7, 2), // VSF
2725
VecBinaryOp::Sub64x2 => (0xe7f7, 3), // VSG
2726
VecBinaryOp::Sub128 => (0xe7f7, 4), // VSQ
2727
VecBinaryOp::Mul8x16 => (0xe7a2, 0), // VMLB
2728
VecBinaryOp::Mul16x8 => (0xe7a2, 1), // VMLHW
2729
VecBinaryOp::Mul32x4 => (0xe7a2, 2), // VMLF
2730
VecBinaryOp::Mul64x2 => (0xe7a2, 3), // VMLG
2731
VecBinaryOp::Mul128 => (0xe7a2, 4), // VMLQ
2732
VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), // VMLHB
2733
VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), // VMLHH
2734
VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), // VMLHF
2735
VecBinaryOp::UMulHi64x2 => (0xe7a1, 3), // VMLHG
2736
VecBinaryOp::UMulHi128 => (0xe7a1, 4), // VMLHQ
2737
VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), // VMHB
2738
VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), // VMHH
2739
VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), // VMHF
2740
VecBinaryOp::SMulHi64x2 => (0xe7a3, 3), // VMHG
2741
VecBinaryOp::SMulHi128 => (0xe7a3, 4), // VMHQ
2742
VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), // VMLEB
2743
VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), // VMLEH
2744
VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), // VMLEF
2745
VecBinaryOp::UMulEven64x2 => (0xe7a4, 3), // VMLEG
2746
VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), // VMEB
2747
VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), // VMEH
2748
VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), // VMEF
2749
VecBinaryOp::SMulEven64x2 => (0xe7a6, 3), // VMEG
2750
VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), // VMLOB
2751
VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), // VMLOH
2752
VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), // VMLOF
2753
VecBinaryOp::UMulOdd64x2 => (0xe7a5, 3), // VMLOG
2754
VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), // VMOB
2755
VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), // VMOH
2756
VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), // VMOF
2757
VecBinaryOp::SMulOdd64x2 => (0xe7a7, 3), // VMOG
2758
VecBinaryOp::UDiv32x4 => (0xe7b0, 2), // VDLF
2759
VecBinaryOp::UDiv64x2 => (0xe7b0, 3), // VDLG
2760
VecBinaryOp::UDiv128 => (0xe7b0, 4), // VDLQ
2761
VecBinaryOp::SDiv32x4 => (0xe7b2, 2), // VDF
2762
VecBinaryOp::SDiv64x2 => (0xe7b2, 3), // VDG
2763
VecBinaryOp::SDiv128 => (0xe7b2, 4), // VDQ
2764
VecBinaryOp::URem32x4 => (0xe7b1, 2), // VRLF
2765
VecBinaryOp::URem64x2 => (0xe7b1, 3), // VRLG
2766
VecBinaryOp::URem128 => (0xe7b1, 4), // VRLQ
2767
VecBinaryOp::SRem32x4 => (0xe7b3, 2), // VRF
2768
VecBinaryOp::SRem64x2 => (0xe7b3, 3), // VRG
2769
VecBinaryOp::SRem128 => (0xe7b3, 4), // VRQ
2770
VecBinaryOp::UMax8x16 => (0xe7fd, 0), // VMXLB
2771
VecBinaryOp::UMax16x8 => (0xe7fd, 1), // VMXLH
2772
VecBinaryOp::UMax32x4 => (0xe7fd, 2), // VMXLF
2773
VecBinaryOp::UMax64x2 => (0xe7fd, 3), // VMXLG
2774
VecBinaryOp::UMax128 => (0xe7fd, 4), // VMXLQ
2775
VecBinaryOp::SMax8x16 => (0xe7ff, 0), // VMXB
2776
VecBinaryOp::SMax16x8 => (0xe7ff, 1), // VMXH
2777
VecBinaryOp::SMax32x4 => (0xe7ff, 2), // VMXF
2778
VecBinaryOp::SMax64x2 => (0xe7ff, 3), // VMXG
2779
VecBinaryOp::SMax128 => (0xe7ff, 4), // VMXQ
2780
VecBinaryOp::UMin8x16 => (0xe7fc, 0), // VMNLB
2781
VecBinaryOp::UMin16x8 => (0xe7fc, 1), // VMNLH
2782
VecBinaryOp::UMin32x4 => (0xe7fc, 2), // VMNLF
2783
VecBinaryOp::UMin64x2 => (0xe7fc, 3), // VMNLG
2784
VecBinaryOp::UMin128 => (0xe7fc, 4), // VMNLQ
2785
VecBinaryOp::SMin8x16 => (0xe7fe, 0), // VMNB
2786
VecBinaryOp::SMin16x8 => (0xe7fe, 1), // VMNH
2787
VecBinaryOp::SMin32x4 => (0xe7fe, 2), // VMNF
2788
VecBinaryOp::SMin64x2 => (0xe7fe, 3), // VMNG
2789
VecBinaryOp::SMin128 => (0xe7fe, 4), // VMNQ
2790
VecBinaryOp::UAvg8x16 => (0xe7f0, 0), // VAVGLB
2791
VecBinaryOp::UAvg16x8 => (0xe7f0, 1), // VAVGLH
2792
VecBinaryOp::UAvg32x4 => (0xe7f0, 2), // VAVGLF
2793
VecBinaryOp::UAvg64x2 => (0xe7f0, 3), // VAVGLG
2794
VecBinaryOp::UAvg128 => (0xe7f0, 4), // VAVGLQ
2795
VecBinaryOp::SAvg8x16 => (0xe7f2, 0), // VAVGB
2796
VecBinaryOp::SAvg16x8 => (0xe7f2, 1), // VAVGH
2797
VecBinaryOp::SAvg32x4 => (0xe7f2, 2), // VAVGF
2798
VecBinaryOp::SAvg64x2 => (0xe7f2, 3), // VAVGG
2799
VecBinaryOp::SAvg128 => (0xe7f2, 4), // VAVGQ
2800
VecBinaryOp::And128 => (0xe768, 0), // VN
2801
VecBinaryOp::Orr128 => (0xe76a, 0), // VO
2802
VecBinaryOp::Xor128 => (0xe76d, 0), // VX
2803
VecBinaryOp::NotAnd128 => (0xe76e, 0), // VNN
2804
VecBinaryOp::NotOrr128 => (0xe76b, 0), // VNO
2805
VecBinaryOp::NotXor128 => (0xe76c, 0), // VNX
2806
VecBinaryOp::AndNot128 => (0xe769, 0), // VNC
2807
VecBinaryOp::OrrNot128 => (0xe76f, 0), // VOC
2808
VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM
2809
VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB
2810
VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB
2811
VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB
2812
VecBinaryOp::LShLByBit128 => (0xe774, 0), // VSL
2813
VecBinaryOp::LShRByBit128 => (0xe77c, 0), // VSRL
2814
VecBinaryOp::AShRByBit128 => (0xe77e, 0), // VSRA
2815
VecBinaryOp::Pack16x8 => (0xe794, 1), // VPKH
2816
VecBinaryOp::Pack32x4 => (0xe794, 2), // VPKF
2817
VecBinaryOp::Pack64x2 => (0xe794, 3), // VPKG
2818
VecBinaryOp::PackUSat16x8 => (0xe795, 1), // VPKLSH
2819
VecBinaryOp::PackUSat32x4 => (0xe795, 2), // VPKLSF
2820
VecBinaryOp::PackUSat64x2 => (0xe795, 3), // VPKLSG
2821
VecBinaryOp::PackSSat16x8 => (0xe797, 1), // VPKSH
2822
VecBinaryOp::PackSSat32x4 => (0xe797, 2), // VPKSF
2823
VecBinaryOp::PackSSat64x2 => (0xe797, 3), // VPKSG
2824
VecBinaryOp::MergeLow8x16 => (0xe760, 0), // VMRLB
2825
VecBinaryOp::MergeLow16x8 => (0xe760, 1), // VMRLH
2826
VecBinaryOp::MergeLow32x4 => (0xe760, 2), // VMRLF
2827
VecBinaryOp::MergeLow64x2 => (0xe760, 3), // VMRLG
2828
VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB
2829
VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH
2830
VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF
2831
VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG
2832
};
2833
2834
let enc = &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0);
2835
let may_trap = match op {
2836
VecBinaryOp::UDiv32x4
2837
| VecBinaryOp::UDiv64x2
2838
| VecBinaryOp::UDiv128
2839
| VecBinaryOp::SDiv32x4
2840
| VecBinaryOp::SDiv64x2
2841
| VecBinaryOp::SDiv128
2842
| VecBinaryOp::URem32x4
2843
| VecBinaryOp::URem64x2
2844
| VecBinaryOp::URem128
2845
| VecBinaryOp::SRem32x4
2846
| VecBinaryOp::SRem64x2
2847
| VecBinaryOp::SRem128 => true,
2848
_ => false,
2849
};
2850
if may_trap {
2851
put_with_trap(sink, enc, TrapCode::INTEGER_DIVISION_BY_ZERO);
2852
} else {
2853
put(sink, enc);
2854
}
2855
}
2856
&Inst::VecRR { op, rd, rn } => {
2857
let (opcode, m3) = match op {
2858
VecUnaryOp::Abs8x16 => (0xe7df, 0), // VLPB
2859
VecUnaryOp::Abs16x8 => (0xe7df, 1), // VLPH
2860
VecUnaryOp::Abs32x4 => (0xe7df, 2), // VLPF
2861
VecUnaryOp::Abs64x2 => (0xe7df, 3), // VLPG
2862
VecUnaryOp::Abs128 => (0xe7df, 4), // VLPQ
2863
VecUnaryOp::Neg8x16 => (0xe7de, 0), // VLCB
2864
VecUnaryOp::Neg16x8 => (0xe7de, 1), // VLCH
2865
VecUnaryOp::Neg32x4 => (0xe7de, 2), // VLCF
2866
VecUnaryOp::Neg64x2 => (0xe7de, 3), // VLCG
2867
VecUnaryOp::Neg128 => (0xe7de, 4), // VLCQ
2868
VecUnaryOp::Popcnt8x16 => (0xe750, 0), // VPOPCTB
2869
VecUnaryOp::Popcnt16x8 => (0xe750, 1), // VPOPCTH
2870
VecUnaryOp::Popcnt32x4 => (0xe750, 2), // VPOPCTF
2871
VecUnaryOp::Popcnt64x2 => (0xe750, 3), // VPOPCTG
2872
VecUnaryOp::Clz8x16 => (0xe753, 0), // VCLZB
2873
VecUnaryOp::Clz16x8 => (0xe753, 1), // VCLZH
2874
VecUnaryOp::Clz32x4 => (0xe753, 2), // VCLZF
2875
VecUnaryOp::Clz64x2 => (0xe753, 3), // VCLZG
2876
VecUnaryOp::Clz128 => (0xe753, 4), // VCLZQ
2877
VecUnaryOp::Ctz8x16 => (0xe752, 0), // VCTZB
2878
VecUnaryOp::Ctz16x8 => (0xe752, 1), // VCTZH
2879
VecUnaryOp::Ctz32x4 => (0xe752, 2), // VCTZF
2880
VecUnaryOp::Ctz64x2 => (0xe752, 3), // VCTZG
2881
VecUnaryOp::Ctz128 => (0xe752, 4), // VCTZQ
2882
VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), // VUPLLB
2883
VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), // VUPLLH
2884
VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), // VUPLLF
2885
VecUnaryOp::UnpackULow64x2 => (0xe7d4, 3), // VUPLLG
2886
VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB
2887
VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH
2888
VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF
2889
VecUnaryOp::UnpackUHigh64x2 => (0xe7d5, 3), // VUPLHG
2890
VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), // VUPLB
2891
VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), // VUPLH
2892
VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), // VUPLF
2893
VecUnaryOp::UnpackSLow64x2 => (0xe7d6, 3), // VUPLG
2894
VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB
2895
VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH
2896
VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF
2897
VecUnaryOp::UnpackSHigh64x2 => (0xe7d7, 3), // VUPHG
2898
};
2899
2900
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0));
2901
}
2902
&Inst::VecShiftRR {
2903
shift_op,
2904
rd,
2905
rn,
2906
shift_imm,
2907
shift_reg,
2908
} => {
2909
let (opcode, m4) = match shift_op {
2910
VecShiftOp::RotL8x16 => (0xe733, 0), // VERLLB
2911
VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH
2912
VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF
2913
VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG
2914
VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB
2915
VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH
2916
VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF
2917
VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG
2918
VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB
2919
VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH
2920
VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF
2921
VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG
2922
VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB
2923
VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH
2924
VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF
2925
VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG
2926
};
2927
put(
2928
sink,
2929
&enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4),
2930
);
2931
}
2932
&Inst::VecSelect { rd, rn, rm, ra } => {
2933
let opcode = 0xe78d; // VSEL
2934
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2935
}
2936
&Inst::VecPermute { rd, rn, rm, ra } => {
2937
let opcode = 0xe78c; // VPERM
2938
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2939
}
2940
&Inst::VecBlend { rd, rn, rm, ra } => {
2941
let opcode = 0xe789; // VBLEND
2942
put(sink, &enc_vrr_d(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2943
}
2944
&Inst::VecEvaluate {
2945
imm,
2946
rd,
2947
rn,
2948
rm,
2949
ra,
2950
} => {
2951
let opcode = 0xe788; //VEVAL
2952
put(sink, &enc_vri_k(opcode, imm, rd.to_reg(), rn, rm, ra));
2953
}
2954
&Inst::VecPermuteDWImm {
2955
rd,
2956
rn,
2957
rm,
2958
idx1,
2959
idx2,
2960
} => {
2961
let m4 = (idx1 & 1) * 4 + (idx2 & 1);
2962
2963
let opcode = 0xe784; // VPDI
2964
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));
2965
}
2966
&Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {
2967
let (opcode, m4) = match op {
2968
VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), // VCEQB
2969
VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), // VCEQH
2970
VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), // VCEQF
2971
VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), // VCEQG
2972
VecIntCmpOp::CmpEq128 => (0xe7f8, 4), // VCEQQ
2973
VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB
2974
VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH
2975
VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG
2976
VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG
2977
VecIntCmpOp::SCmpHi128 => (0xe7fb, 4), // VCHQ
2978
VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB
2979
VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH
2980
VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG
2981
VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG
2982
VecIntCmpOp::UCmpHi128 => (0xe7f9, 4), // VCHLQ
2983
};
2984
let m5 = match self {
2985
&Inst::VecIntCmp { .. } => 0,
2986
&Inst::VecIntCmpS { .. } => 1,
2987
_ => unreachable!(),
2988
};
2989
2990
put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5));
2991
}
2992
&Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {
2993
let (opcode, m4) = match op {
2994
VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), // VFCESB
2995
VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), // VFCEDB
2996
VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), // VFCHSB
2997
VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), // VFCHDB
2998
VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB
2999
VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB
3000
};
3001
let m6 = match self {
3002
&Inst::VecFloatCmp { .. } => 0,
3003
&Inst::VecFloatCmpS { .. } => 1,
3004
_ => unreachable!(),
3005
};
3006
3007
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6));
3008
}
3009
&Inst::VecIntEltCmp { op, rn, rm } => {
3010
let (opcode, m3) = match op {
3011
VecIntEltCmpOp::SCmp128 => (0xe7db, 4), // VECQ
3012
VecIntEltCmpOp::UCmp128 => (0xe7d9, 4), // VECLQ
3013
};
3014
3015
put(sink, &enc_vrr_a(opcode, rn, rm, m3, 0, 0));
3016
}
3017
&Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {
3018
// Synthetic instruction to compare 128-bit values.
3019
// Sets CC 1 if rn > rm, sets a different CC otherwise.
3020
3021
// Use VECTOR ELEMENT COMPARE to compare the high parts.
3022
// Swap the inputs to get:
3023
// CC 1 if high(rn) > high(rm)
3024
// CC 2 if high(rn) < high(rm)
3025
// CC 0 if high(rn) == high(rm)
3026
let (opcode, m3) = match self {
3027
&Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG
3028
&Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG
3029
_ => unreachable!(),
3030
};
3031
put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));
3032
3033
// If CC != 0, we'd done, so jump over the next instruction.
3034
put(sink, &enc_ri_c(OPCODE_BCR, 7, 4 + 6));
3035
3036
// Otherwise, use VECTOR COMPARE HIGH LOGICAL.
3037
// Since we already know the high parts are equal, the CC
3038
// result will only depend on the low parts:
3039
// CC 1 if low(rn) > low(rm)
3040
// CC 3 if low(rn) <= low(rm)
3041
let inst = Inst::VecIntCmpS {
3042
op: VecIntCmpOp::UCmpHi64x2,
3043
// N.B.: This is the first write to tmp, and it happens
3044
// after all uses of rn and rm. If this were to ever
3045
// change, tmp would have to become an early-def.
3046
rd: tmp,
3047
rn,
3048
rm,
3049
};
3050
inst.emit(sink, emit_info, state);
3051
}
3052
3053
&Inst::VecLoad { rd, ref mem }
3054
| &Inst::VecLoadRev { rd, ref mem }
3055
| &Inst::VecLoadByte16Rev { rd, ref mem }
3056
| &Inst::VecLoadByte32Rev { rd, ref mem }
3057
| &Inst::VecLoadByte64Rev { rd, ref mem }
3058
| &Inst::VecLoadElt16Rev { rd, ref mem }
3059
| &Inst::VecLoadElt32Rev { rd, ref mem }
3060
| &Inst::VecLoadElt64Rev { rd, ref mem } => {
3061
let mem = mem.clone();
3062
3063
let (opcode, m3) = match self {
3064
&Inst::VecLoad { .. } => (0xe706, 0), // VL
3065
&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ
3066
&Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH
3067
&Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF
3068
&Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG
3069
&Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH
3070
&Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF
3071
&Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG
3072
_ => unreachable!(),
3073
};
3074
mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
3075
}
3076
&Inst::VecStore { rd, ref mem }
3077
| &Inst::VecStoreRev { rd, ref mem }
3078
| &Inst::VecStoreByte16Rev { rd, ref mem }
3079
| &Inst::VecStoreByte32Rev { rd, ref mem }
3080
| &Inst::VecStoreByte64Rev { rd, ref mem }
3081
| &Inst::VecStoreElt16Rev { rd, ref mem }
3082
| &Inst::VecStoreElt32Rev { rd, ref mem }
3083
| &Inst::VecStoreElt64Rev { rd, ref mem } => {
3084
let mem = mem.clone();
3085
3086
let (opcode, m3) = match self {
3087
&Inst::VecStore { .. } => (0xe70e, 0), // VST
3088
&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ
3089
&Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH
3090
&Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF
3091
&Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG
3092
&Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH
3093
&Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF
3094
&Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG
3095
_ => unreachable!(),
3096
};
3097
mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);
3098
}
3099
&Inst::VecLoadReplicate { size, rd, ref mem }
3100
| &Inst::VecLoadReplicateRev { size, rd, ref mem } => {
3101
let mem = mem.clone();
3102
3103
let (opcode, m3) = match (self, size) {
3104
(&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), // VLREPB
3105
(&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH
3106
(&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF
3107
(&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG
3108
(&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH
3109
(&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF
3110
(&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG
3111
_ => unreachable!(),
3112
};
3113
mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
3114
}
3115
3116
&Inst::VecMov { rd, rn } => {
3117
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
3118
}
3119
&Inst::VecCMov { rd, cond, ri, rm } => {
3120
debug_assert_eq!(rd.to_reg(), ri);
3121
3122
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
3123
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
3124
}
3125
&Inst::MovToVec128 { rd, rn, rm } => {
3126
let opcode = 0xe762; // VLVGP
3127
put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));
3128
}
3129
&Inst::VecImmByteMask { rd, mask } => {
3130
let opcode = 0xe744; // VGBM
3131
put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0));
3132
}
3133
&Inst::VecImmBitMask {
3134
size,
3135
rd,
3136
start_bit,
3137
end_bit,
3138
} => {
3139
let (opcode, m4) = match size {
3140
8 => (0xe746, 0), // VGMB
3141
16 => (0xe746, 1), // VGMH
3142
32 => (0xe746, 2), // VGMF
3143
64 => (0xe746, 3), // VGMG
3144
_ => unreachable!(),
3145
};
3146
put(
3147
sink,
3148
&enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4),
3149
);
3150
}
3151
&Inst::VecImmReplicate { size, rd, imm } => {
3152
let (opcode, m3) = match size {
3153
8 => (0xe745, 0), // VREPIB
3154
16 => (0xe745, 1), // VREPIH
3155
32 => (0xe745, 2), // VREPIF
3156
64 => (0xe745, 3), // VREPIG
3157
_ => unreachable!(),
3158
};
3159
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3));
3160
}
3161
&Inst::VecLoadLane {
3162
size,
3163
rd,
3164
ri,
3165
ref mem,
3166
lane_imm,
3167
}
3168
| &Inst::VecLoadLaneRev {
3169
size,
3170
rd,
3171
ri,
3172
ref mem,
3173
lane_imm,
3174
} => {
3175
debug_assert_eq!(rd.to_reg(), ri);
3176
let mem = mem.clone();
3177
3178
let opcode_vrx = match (self, size) {
3179
(&Inst::VecLoadLane { .. }, 8) => 0xe700, // VLEB
3180
(&Inst::VecLoadLane { .. }, 16) => 0xe701, // VLEH
3181
(&Inst::VecLoadLane { .. }, 32) => 0xe703, // VLEF
3182
(&Inst::VecLoadLane { .. }, 64) => 0xe702, // VLEG
3183
(&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH
3184
(&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF
3185
(&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG
3186
_ => unreachable!(),
3187
};
3188
3189
let rd = rd.to_reg();
3190
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3191
}
3192
&Inst::VecLoadLaneUndef {
3193
size,
3194
rd,
3195
ref mem,
3196
lane_imm,
3197
}
3198
| &Inst::VecLoadLaneRevUndef {
3199
size,
3200
rd,
3201
ref mem,
3202
lane_imm,
3203
} => {
3204
let mem = mem.clone();
3205
3206
let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3207
(&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), // VLEB
3208
(&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH
3209
(&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y)
3210
(&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y)
3211
(&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH
3212
(&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF
3213
(&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG
3214
_ => unreachable!(),
3215
};
3216
3217
let rd = rd.to_reg();
3218
if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3219
mem_emit(
3220
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3221
);
3222
} else {
3223
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3224
}
3225
}
3226
&Inst::VecStoreLane {
3227
size,
3228
rd,
3229
ref mem,
3230
lane_imm,
3231
}
3232
| &Inst::VecStoreLaneRev {
3233
size,
3234
rd,
3235
ref mem,
3236
lane_imm,
3237
} => {
3238
let mem = mem.clone();
3239
3240
let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3241
(&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), // VSTEB
3242
(&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH
3243
(&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y)
3244
(&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y)
3245
(&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH
3246
(&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF
3247
(&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG
3248
_ => unreachable!(),
3249
};
3250
3251
if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3252
mem_emit(
3253
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3254
);
3255
} else {
3256
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3257
}
3258
}
3259
&Inst::VecInsertLane {
3260
size,
3261
rd,
3262
ri,
3263
rn,
3264
lane_imm,
3265
lane_reg,
3266
} => {
3267
debug_assert_eq!(rd.to_reg(), ri);
3268
3269
let (opcode_vrs, m4) = match size {
3270
8 => (0xe722, 0), // VLVGB
3271
16 => (0xe722, 1), // VLVGH
3272
32 => (0xe722, 2), // VLVGF
3273
64 => (0xe722, 3), // VLVGG
3274
_ => unreachable!(),
3275
};
3276
put(
3277
sink,
3278
&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3279
);
3280
}
3281
&Inst::VecInsertLaneUndef {
3282
size,
3283
rd,
3284
rn,
3285
lane_imm,
3286
lane_reg,
3287
} => {
3288
let (opcode_vrs, m4, opcode_rre) = match size {
3289
8 => (0xe722, 0, None), // VLVGB
3290
16 => (0xe722, 1, None), // VLVGH
3291
32 => (0xe722, 2, None), // VLVGF
3292
64 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR
3293
_ => unreachable!(),
3294
};
3295
if opcode_rre.is_some()
3296
&& lane_imm == 0
3297
&& lane_reg == zero_reg()
3298
&& is_fpr(rd.to_reg())
3299
{
3300
put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3301
} else {
3302
put(
3303
sink,
3304
&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3305
);
3306
}
3307
}
3308
&Inst::VecExtractLane {
3309
size,
3310
rd,
3311
rn,
3312
lane_imm,
3313
lane_reg,
3314
} => {
3315
let (opcode_vrs, m4, opcode_rre) = match size {
3316
8 => (0xe721, 0, None), // VLGVB
3317
16 => (0xe721, 1, None), // VLGVH
3318
32 => (0xe721, 2, None), // VLGVF
3319
64 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR
3320
_ => unreachable!(),
3321
};
3322
if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) {
3323
put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3324
} else {
3325
put(
3326
sink,
3327
&enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3328
);
3329
}
3330
}
3331
&Inst::VecInsertLaneImm {
3332
size,
3333
rd,
3334
ri,
3335
imm,
3336
lane_imm,
3337
} => {
3338
debug_assert_eq!(rd.to_reg(), ri);
3339
3340
let opcode = match size {
3341
8 => 0xe740, // VLEIB
3342
16 => 0xe741, // VLEIH
3343
32 => 0xe743, // VLEIF
3344
64 => 0xe742, // VLEIG
3345
_ => unreachable!(),
3346
};
3347
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));
3348
}
3349
&Inst::VecInsertLaneImmUndef {
3350
size,
3351
rd,
3352
imm,
3353
lane_imm,
3354
} => {
3355
let opcode = match size {
3356
8 => 0xe740, // VLEIB
3357
16 => 0xe741, // VLEIH
3358
32 => 0xe743, // VLEIF
3359
64 => 0xe742, // VLEIG
3360
_ => unreachable!(),
3361
};
3362
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));
3363
}
3364
&Inst::VecReplicateLane {
3365
size,
3366
rd,
3367
rn,
3368
lane_imm,
3369
} => {
3370
let (opcode, m4) = match size {
3371
8 => (0xe74d, 0), // VREPB
3372
16 => (0xe74d, 1), // VREPH
3373
32 => (0xe74d, 2), // VREPF
3374
64 => (0xe74d, 3), // VREPG
3375
_ => unreachable!(),
3376
};
3377
put(
3378
sink,
3379
&enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4),
3380
);
3381
}
3382
3383
&Inst::VecEltRev { lane_count, rd, rn } => {
3384
assert!(lane_count >= 2 && lane_count <= 16);
3385
let inst = Inst::VecPermuteDWImm {
3386
rd,
3387
rn,
3388
rm: rn,
3389
idx1: 1,
3390
idx2: 0,
3391
};
3392
inst.emit(sink, emit_info, state);
3393
if lane_count >= 4 {
3394
let inst = Inst::VecShiftRR {
3395
shift_op: VecShiftOp::RotL64x2,
3396
rd,
3397
rn: rd.to_reg(),
3398
shift_imm: 32,
3399
shift_reg: zero_reg(),
3400
};
3401
inst.emit(sink, emit_info, state);
3402
}
3403
if lane_count >= 8 {
3404
let inst = Inst::VecShiftRR {
3405
shift_op: VecShiftOp::RotL32x4,
3406
rd,
3407
rn: rd.to_reg(),
3408
shift_imm: 16,
3409
shift_reg: zero_reg(),
3410
};
3411
inst.emit(sink, emit_info, state);
3412
}
3413
if lane_count >= 16 {
3414
let inst = Inst::VecShiftRR {
3415
shift_op: VecShiftOp::RotL16x8,
3416
rd,
3417
rn: rd.to_reg(),
3418
shift_imm: 8,
3419
shift_reg: zero_reg(),
3420
};
3421
inst.emit(sink, emit_info, state);
3422
}
3423
}
3424
3425
&Inst::AllocateArgs { size } => {
3426
let inst = if let Ok(size) = i16::try_from(size) {
3427
Inst::AluRSImm16 {
3428
alu_op: ALUOp::Add64,
3429
rd: writable_stack_reg(),
3430
ri: stack_reg(),
3431
imm: -size,
3432
}
3433
} else {
3434
Inst::AluRUImm32 {
3435
alu_op: ALUOp::SubLogical64,
3436
rd: writable_stack_reg(),
3437
ri: stack_reg(),
3438
imm: size,
3439
}
3440
};
3441
inst.emit(sink, emit_info, state);
3442
assert_eq!(state.nominal_sp_offset, 0);
3443
state.nominal_sp_offset += size;
3444
}
3445
&Inst::Call { link, ref info } => {
3446
let start = sink.cur_offset();
3447
3448
let enc: &[u8] = match &info.dest {
3449
CallInstDest::Direct { name } => {
3450
let offset = sink.cur_offset() + 2;
3451
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);
3452
let opcode = 0xc05; // BRASL
3453
&enc_ril_b(opcode, link.to_reg(), 0)
3454
}
3455
CallInstDest::Indirect { reg } => {
3456
let opcode = 0x0d; // BASR
3457
&enc_rr(opcode, link.to_reg(), *reg)
3458
}
3459
};
3460
if let Some(s) = state.take_stack_map() {
3461
let offset = sink.cur_offset() + enc.len() as u32;
3462
sink.push_user_stack_map(state, offset, s);
3463
}
3464
put(sink, enc);
3465
3466
if let Some(try_call) = info.try_call_info.as_ref() {
3467
sink.add_try_call_site(
3468
Some(state.frame_layout.sp_to_fp()),
3469
try_call.exception_handlers(&state.frame_layout),
3470
);
3471
} else {
3472
sink.add_call_site();
3473
}
3474
3475
state.nominal_sp_offset -= info.callee_pop_size;
3476
assert_eq!(state.nominal_sp_offset, 0);
3477
3478
if info.patchable {
3479
sink.add_patchable_call_site(sink.cur_offset() - start);
3480
} else {
3481
state.outgoing_sp_offset = info.callee_pop_size;
3482
for inst in S390xMachineDeps::gen_retval_loads(info) {
3483
inst.emit(sink, emit_info, state);
3484
}
3485
state.outgoing_sp_offset = 0;
3486
}
3487
3488
// If this is a try-call, jump to the continuation
3489
// (normal-return) block.
3490
if let Some(try_call) = info.try_call_info.as_ref() {
3491
let jmp = Inst::Jump {
3492
dest: try_call.continuation,
3493
};
3494
jmp.emit(sink, emit_info, state);
3495
}
3496
}
3497
&Inst::ReturnCall { ref info } => {
3498
let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(
3499
state.frame_layout(),
3500
info.callee_pop_size,
3501
&info.dest,
3502
);
3503
for inst in epilogue_insts {
3504
inst.emit(sink, emit_info, state);
3505
}
3506
3507
let enc: &[u8] = match &info.dest {
3508
CallInstDest::Direct { name } => {
3509
let offset = sink.cur_offset() + 2;
3510
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);
3511
let opcode = 0xc04; // BCRL
3512
&enc_ril_c(opcode, 15, 0)
3513
}
3514
CallInstDest::Indirect { reg } => {
3515
let opcode = 0x07; // BCR
3516
&enc_rr(opcode, gpr(15), temp_dest.unwrap_or(*reg))
3517
}
3518
};
3519
put(sink, enc);
3520
sink.add_call_site();
3521
}
3522
&Inst::ElfTlsGetOffset { ref symbol, .. } => {
3523
let opcode = 0xc05; // BRASL
3524
3525
// Add relocation for target function. This has to be done
3526
// *before* the S390xTlsGdCall, to ensure linker relaxation
3527
// works correctly.
3528
let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset);
3529
let offset = sink.cur_offset() + 2;
3530
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2);
3531
match &**symbol {
3532
SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0),
3533
_ => unreachable!(),
3534
}
3535
3536
put(sink, &enc_ril_b(opcode, gpr(14), 0));
3537
sink.add_call_site();
3538
}
3539
&Inst::Args { .. } => {}
3540
&Inst::Rets { .. } => {}
3541
&Inst::Ret { link } => {
3542
let opcode = 0x07; // BCR
3543
put(sink, &enc_rr(opcode, gpr(15), link));
3544
}
3545
&Inst::Jump { dest } => {
3546
let off = sink.cur_offset();
3547
// Indicate that the jump uses a label, if so, so that a fixup can occur later.
3548
sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);
3549
sink.add_uncond_branch(off, off + 6, dest);
3550
// Emit the jump itself.
3551
let opcode = 0xc04; // BCRL
3552
put(sink, &enc_ril_c(opcode, 15, 0));
3553
}
3554
&Inst::IndirectBr { rn, .. } => {
3555
let opcode = 0x07; // BCR
3556
put(sink, &enc_rr(opcode, gpr(15), rn));
3557
}
3558
&Inst::CondBr {
3559
taken,
3560
not_taken,
3561
cond,
3562
} => {
3563
let opcode = 0xc04; // BCRL
3564
3565
// Conditional part first.
3566
let cond_off = sink.cur_offset();
3567
sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);
3568
let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);
3569
sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);
3570
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
3571
3572
// Unconditional part next.
3573
let uncond_off = sink.cur_offset();
3574
sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);
3575
sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);
3576
put(sink, &enc_ril_c(opcode, 15, 0));
3577
}
3578
&Inst::Nop0 => {}
3579
&Inst::Nop2 => {
3580
put(sink, &enc_e(0x0707));
3581
}
3582
&Inst::Debugtrap => {
3583
put(sink, &enc_e(0x0001));
3584
}
3585
&Inst::Trap { trap_code } => {
3586
put_with_trap(sink, &enc_e(0x0000), trap_code);
3587
}
3588
&Inst::TrapIf { cond, trap_code } => {
3589
// We implement a TrapIf as a conditional branch into the middle
3590
// of the branch (BRCL) instruction itself - those middle two bytes
3591
// are zero, which matches the trap instruction itself.
3592
let opcode = 0xc04; // BCRL
3593
let enc = &enc_ril_c(opcode, cond.bits(), 2);
3594
debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);
3595
// The trap must be placed on the last byte of the embedded trap
3596
// instruction, so we need to emit the encoding in two parts.
3597
put_with_trap(sink, &enc[0..4], trap_code);
3598
put(sink, &enc[4..6]);
3599
}
3600
&Inst::JTSequence {
3601
ridx,
3602
default,
3603
default_cond,
3604
ref targets,
3605
} => {
3606
let table_label = sink.get_label();
3607
3608
// This sequence is *one* instruction in the vcode, and is expanded only here at
3609
// emission time, because we cannot allow the regalloc to insert spills/reloads in
3610
// the middle; we depend on hardcoded PC-rel addressing below.
3611
3612
// Branch to the default target if the given default condition is true.
3613
let opcode = 0xc04; // BCRL
3614
sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);
3615
put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));
3616
3617
// Set temp register to address of jump table.
3618
let rtmp = writable_spilltmp_reg();
3619
let inst = Inst::LoadAddr {
3620
rd: rtmp,
3621
mem: MemArg::Label {
3622
target: table_label,
3623
},
3624
};
3625
inst.emit(sink, emit_info, state);
3626
3627
// Set temp to target address by adding the value of the jump table entry.
3628
let inst = Inst::AluRX {
3629
alu_op: ALUOp::Add64Ext32,
3630
rd: rtmp,
3631
ri: rtmp.to_reg(),
3632
mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),
3633
};
3634
inst.emit(sink, emit_info, state);
3635
3636
// Branch to computed address. (`targets` here is only used for successor queries
3637
// and is not needed for emission.)
3638
let inst = Inst::IndirectBr {
3639
rn: rtmp.to_reg(),
3640
targets: vec![],
3641
};
3642
inst.emit(sink, emit_info, state);
3643
3644
// Emit jump table (table of 32-bit offsets).
3645
sink.bind_label(table_label, &mut state.ctrl_plane);
3646
let jt_off = sink.cur_offset();
3647
for &target in targets.iter() {
3648
let word_off = sink.cur_offset();
3649
let off_into_table = word_off - jt_off;
3650
sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3651
sink.put4(off_into_table.swap_bytes());
3652
}
3653
}
3654
3655
Inst::StackProbeLoop {
3656
probe_count,
3657
guard_size,
3658
} => {
3659
// Emit the loop start label
3660
let loop_start = sink.get_label();
3661
sink.bind_label(loop_start, state.ctrl_plane_mut());
3662
3663
// aghi %r15, -GUARD_SIZE
3664
let inst = Inst::AluRSImm16 {
3665
alu_op: ALUOp::Add64,
3666
rd: writable_stack_reg(),
3667
ri: stack_reg(),
3668
imm: -guard_size,
3669
};
3670
inst.emit(sink, emit_info, state);
3671
3672
// mvi 0(%r15), 0
3673
let inst = Inst::StoreImm8 {
3674
imm: 0,
3675
mem: MemArg::reg(stack_reg(), MemFlags::trusted()),
3676
};
3677
inst.emit(sink, emit_info, state);
3678
3679
// brct PROBE_COUNT, LOOP_START
3680
let opcode = 0xa76; // BRCT
3681
sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI);
3682
put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0));
3683
}
3684
3685
&Inst::Unwind { ref inst } => {
3686
sink.add_unwind(inst.clone());
3687
}
3688
3689
&Inst::DummyUse { .. } => {}
3690
3691
&Inst::LabelAddress { dst, label } => {
3692
let inst = Inst::LoadAddr {
3693
rd: dst,
3694
mem: MemArg::Label { target: label },
3695
};
3696
inst.emit(sink, emit_info, state);
3697
}
3698
3699
&Inst::SequencePoint { .. } => {
3700
// Nothing.
3701
}
3702
}
3703
3704
state.clear_post_insn();
3705
}
3706
}
3707
3708