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
1693 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
/// VRRa-type instructions.
1076
///
1077
/// 47 39 35 31 23 19 15 11 7
1078
/// opcode1 v1 v2 - m5 m3 m2 rxb opcode2
1079
/// 40 36 32 24 20 16 12 8 0
1080
///
1081
fn enc_vrr_a(opcode: u16, v1: Reg, v2: Reg, m3: u8, m4: u8, m5: u8) -> [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), None, None);
1085
let v1 = machreg_to_vr(v1) & 0x0f;
1086
let v2 = machreg_to_vr(v2) & 0x0f;
1087
let m3 = m3 & 0x0f;
1088
let m4 = m4 & 0x0f;
1089
let m5 = m5 & 0x0f;
1090
1091
let mut enc: [u8; 6] = [0; 6];
1092
enc[0] = opcode1;
1093
enc[1] = v1 << 4 | v2;
1094
enc[2] = 0;
1095
enc[3] = m5 << 4 | m4;
1096
enc[4] = m3 << 4 | rxb;
1097
enc[5] = opcode2;
1098
enc
1099
}
1100
1101
/// VRRb-type instructions.
1102
///
1103
/// 47 39 35 31 27 23 19 15 11 7
1104
/// opcode1 v1 v2 v3 - m5 - m4 rxb opcode2
1105
/// 40 36 32 28 24 20 16 12 8 0
1106
///
1107
fn enc_vrr_b(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8) -> [u8; 6] {
1108
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1109
let opcode2 = (opcode & 0xff) as u8;
1110
let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1111
let v1 = machreg_to_vr(v1) & 0x0f;
1112
let v2 = machreg_to_vr(v2) & 0x0f;
1113
let v3 = machreg_to_vr(v3) & 0x0f;
1114
let m4 = m4 & 0x0f;
1115
let m5 = m5 & 0x0f;
1116
1117
let mut enc: [u8; 6] = [0; 6];
1118
enc[0] = opcode1;
1119
enc[1] = v1 << 4 | v2;
1120
enc[2] = v3 << 4;
1121
enc[3] = m5 << 4;
1122
enc[4] = m4 << 4 | rxb;
1123
enc[5] = opcode2;
1124
enc
1125
}
1126
1127
/// VRRc-type instructions.
1128
///
1129
/// 47 39 35 31 27 23 19 15 11 7
1130
/// opcode1 v1 v2 v3 - m6 m5 m4 rxb opcode2
1131
/// 40 36 32 28 24 20 16 12 8 0
1132
///
1133
fn enc_vrr_c(opcode: u16, v1: Reg, v2: Reg, v3: Reg, m4: u8, m5: u8, m6: u8) -> [u8; 6] {
1134
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1135
let opcode2 = (opcode & 0xff) as u8;
1136
let rxb = rxb(Some(v1), Some(v2), Some(v3), None);
1137
let v1 = machreg_to_vr(v1) & 0x0f;
1138
let v2 = machreg_to_vr(v2) & 0x0f;
1139
let v3 = machreg_to_vr(v3) & 0x0f;
1140
let m4 = m4 & 0x0f;
1141
let m5 = m5 & 0x0f;
1142
let m6 = m6 & 0x0f;
1143
1144
let mut enc: [u8; 6] = [0; 6];
1145
enc[0] = opcode1;
1146
enc[1] = v1 << 4 | v2;
1147
enc[2] = v3 << 4;
1148
enc[3] = m6 << 4 | m5;
1149
enc[4] = m4 << 4 | rxb;
1150
enc[5] = opcode2;
1151
enc
1152
}
1153
1154
/// VRRe-type instructions.
1155
///
1156
/// 47 39 35 31 27 23 19 15 11 7
1157
/// opcode1 v1 v2 v3 m6 - m5 v4 rxb opcode2
1158
/// 40 36 32 28 24 20 16 12 8 0
1159
///
1160
fn enc_vrr_e(opcode: u16, v1: Reg, v2: Reg, v3: Reg, v4: Reg, m5: u8, m6: u8) -> [u8; 6] {
1161
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1162
let opcode2 = (opcode & 0xff) as u8;
1163
let rxb = rxb(Some(v1), Some(v2), Some(v3), Some(v4));
1164
let v1 = machreg_to_vr(v1) & 0x0f;
1165
let v2 = machreg_to_vr(v2) & 0x0f;
1166
let v3 = machreg_to_vr(v3) & 0x0f;
1167
let v4 = machreg_to_vr(v4) & 0x0f;
1168
let m5 = m5 & 0x0f;
1169
let m6 = m6 & 0x0f;
1170
1171
let mut enc: [u8; 6] = [0; 6];
1172
enc[0] = opcode1;
1173
enc[1] = v1 << 4 | v2;
1174
enc[2] = v3 << 4 | m6;
1175
enc[3] = m5;
1176
enc[4] = v4 << 4 | rxb;
1177
enc[5] = opcode2;
1178
enc
1179
}
1180
1181
/// VRRf-type instructions.
1182
///
1183
/// 47 39 35 31 27 11 7
1184
/// opcode1 v1 r2 r3 - rxb opcode2
1185
/// 40 36 32 28 12 8 0
1186
///
1187
fn enc_vrr_f(opcode: u16, v1: Reg, r2: Reg, r3: Reg) -> [u8; 6] {
1188
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1189
let opcode2 = (opcode & 0xff) as u8;
1190
let rxb = rxb(Some(v1), None, None, None);
1191
let v1 = machreg_to_vr(v1) & 0x0f;
1192
let r2 = machreg_to_gpr(r2) & 0x0f;
1193
let r3 = machreg_to_gpr(r3) & 0x0f;
1194
1195
let mut enc: [u8; 6] = [0; 6];
1196
enc[0] = opcode1;
1197
enc[1] = v1 << 4 | r2;
1198
enc[2] = r3 << 4;
1199
enc[4] = rxb;
1200
enc[5] = opcode2;
1201
enc
1202
}
1203
1204
/// VRSa-type instructions.
1205
///
1206
/// 47 39 35 31 27 15 11 7
1207
/// opcode1 v1 v3 b2 d2 m4 rxb opcode2
1208
/// 40 36 32 28 16 12 8 0
1209
///
1210
fn enc_vrs_a(opcode: u16, v1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1211
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1212
let opcode2 = (opcode & 0xff) as u8;
1213
let rxb = rxb(Some(v1), Some(v3), None, None);
1214
let v1 = machreg_to_vr(v1) & 0x0f;
1215
let b2 = machreg_to_gpr(b2) & 0x0f;
1216
let v3 = machreg_to_vr(v3) & 0x0f;
1217
let d2_lo = (d2 & 0xff) as u8;
1218
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1219
let m4 = m4 & 0x0f;
1220
1221
let mut enc: [u8; 6] = [0; 6];
1222
enc[0] = opcode1;
1223
enc[1] = v1 << 4 | v3;
1224
enc[2] = b2 << 4 | d2_hi;
1225
enc[3] = d2_lo;
1226
enc[4] = m4 << 4 | rxb;
1227
enc[5] = opcode2;
1228
enc
1229
}
1230
1231
/// VRSb-type instructions.
1232
///
1233
/// 47 39 35 31 27 15 11 7
1234
/// opcode1 v1 r3 b2 d2 m4 rxb opcode2
1235
/// 40 36 32 28 16 12 8 0
1236
///
1237
fn enc_vrs_b(opcode: u16, v1: Reg, b2: Reg, d2: u32, r3: Reg, m4: u8) -> [u8; 6] {
1238
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1239
let opcode2 = (opcode & 0xff) as u8;
1240
let rxb = rxb(Some(v1), None, None, None);
1241
let v1 = machreg_to_vr(v1) & 0x0f;
1242
let b2 = machreg_to_gpr(b2) & 0x0f;
1243
let r3 = machreg_to_gpr(r3) & 0x0f;
1244
let d2_lo = (d2 & 0xff) as u8;
1245
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1246
let m4 = m4 & 0x0f;
1247
1248
let mut enc: [u8; 6] = [0; 6];
1249
enc[0] = opcode1;
1250
enc[1] = v1 << 4 | r3;
1251
enc[2] = b2 << 4 | d2_hi;
1252
enc[3] = d2_lo;
1253
enc[4] = m4 << 4 | rxb;
1254
enc[5] = opcode2;
1255
enc
1256
}
1257
1258
/// VRSc-type instructions.
1259
///
1260
/// 47 39 35 31 27 15 11 7
1261
/// opcode1 r1 v3 b2 d2 m4 rxb opcode2
1262
/// 40 36 32 28 16 12 8 0
1263
///
1264
fn enc_vrs_c(opcode: u16, r1: Reg, b2: Reg, d2: u32, v3: Reg, m4: u8) -> [u8; 6] {
1265
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1266
let opcode2 = (opcode & 0xff) as u8;
1267
let rxb = rxb(None, Some(v3), None, None);
1268
let r1 = machreg_to_gpr(r1) & 0x0f;
1269
let b2 = machreg_to_gpr(b2) & 0x0f;
1270
let v3 = machreg_to_vr(v3) & 0x0f;
1271
let d2_lo = (d2 & 0xff) as u8;
1272
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1273
let m4 = m4 & 0x0f;
1274
1275
let mut enc: [u8; 6] = [0; 6];
1276
enc[0] = opcode1;
1277
enc[1] = r1 << 4 | v3;
1278
enc[2] = b2 << 4 | d2_hi;
1279
enc[3] = d2_lo;
1280
enc[4] = m4 << 4 | rxb;
1281
enc[5] = opcode2;
1282
enc
1283
}
1284
1285
/// VRX-type instructions.
1286
///
1287
/// 47 39 35 31 27 15 11 7
1288
/// opcode1 v1 x2 b2 d2 m3 rxb opcode2
1289
/// 40 36 32 28 16 12 8 0
1290
///
1291
fn enc_vrx(opcode: u16, v1: Reg, b2: Reg, x2: Reg, d2: u32, m3: u8) -> [u8; 6] {
1292
let opcode1 = ((opcode >> 8) & 0xff) as u8;
1293
let opcode2 = (opcode & 0xff) as u8;
1294
let rxb = rxb(Some(v1), None, None, None);
1295
let v1 = machreg_to_vr(v1) & 0x0f;
1296
let b2 = machreg_to_gpr(b2) & 0x0f;
1297
let x2 = machreg_to_gpr(x2) & 0x0f;
1298
let d2_lo = (d2 & 0xff) as u8;
1299
let d2_hi = ((d2 >> 8) & 0x0f) as u8;
1300
let m3 = m3 & 0x0f;
1301
1302
let mut enc: [u8; 6] = [0; 6];
1303
enc[0] = opcode1;
1304
enc[1] = v1 << 4 | x2;
1305
enc[2] = b2 << 4 | d2_hi;
1306
enc[3] = d2_lo;
1307
enc[4] = m3 << 4 | rxb;
1308
enc[5] = opcode2;
1309
enc
1310
}
1311
1312
/// Emit encoding to sink.
1313
fn put(sink: &mut MachBuffer<Inst>, enc: &[u8]) {
1314
for byte in enc {
1315
sink.put1(*byte);
1316
}
1317
}
1318
1319
/// Emit encoding to sink, adding a trap on the last byte.
1320
fn put_with_trap(sink: &mut MachBuffer<Inst>, enc: &[u8], trap_code: TrapCode) {
1321
let len = enc.len();
1322
for i in 0..len - 1 {
1323
sink.put1(enc[i]);
1324
}
1325
sink.add_trap(trap_code);
1326
sink.put1(enc[len - 1]);
1327
}
1328
1329
/// State carried between emissions of a sequence of instructions.
1330
#[derive(Default, Clone, Debug)]
1331
pub struct EmitState {
1332
/// Offset from the actual SP to the "nominal SP". The latter is defined
1333
/// as the value the stack pointer has after the prolog. This offset is
1334
/// normally always zero, except during a call sequence using the tail-call
1335
/// ABI, between the AllocateArgs and the actual call instruction.
1336
pub(crate) nominal_sp_offset: u32,
1337
1338
/// Offset from the actual SP to the SP during an outgoing function call.
1339
/// This is normally always zero, except during processing of the return
1340
/// argument handling after a call using the tail-call ABI has returned.
1341
pub(crate) outgoing_sp_offset: u32,
1342
1343
/// Size of the incoming argument area in the caller's frame. Always zero
1344
/// for functions using the tail-call ABI.
1345
pub(crate) incoming_args_size: u32,
1346
1347
/// The user stack map for the upcoming instruction, as provided to
1348
/// `pre_safepoint()`.
1349
user_stack_map: Option<ir::UserStackMap>,
1350
1351
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
1352
/// optimized away at compiletime. See [cranelift_control].
1353
ctrl_plane: ControlPlane,
1354
1355
frame_layout: FrameLayout,
1356
}
1357
1358
impl MachInstEmitState<Inst> for EmitState {
1359
fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {
1360
let incoming_args_size = if abi.call_conv() == CallConv::Tail {
1361
0
1362
} else {
1363
abi.frame_layout().incoming_args_size
1364
};
1365
EmitState {
1366
nominal_sp_offset: 0,
1367
outgoing_sp_offset: 0,
1368
incoming_args_size,
1369
user_stack_map: None,
1370
ctrl_plane,
1371
frame_layout: abi.frame_layout().clone(),
1372
}
1373
}
1374
1375
fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
1376
self.user_stack_map = user_stack_map;
1377
}
1378
1379
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
1380
&mut self.ctrl_plane
1381
}
1382
1383
fn take_ctrl_plane(self) -> ControlPlane {
1384
self.ctrl_plane
1385
}
1386
1387
fn frame_layout(&self) -> &FrameLayout {
1388
&self.frame_layout
1389
}
1390
}
1391
1392
impl EmitState {
1393
fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
1394
self.user_stack_map.take()
1395
}
1396
1397
fn clear_post_insn(&mut self) {
1398
self.user_stack_map = None;
1399
}
1400
}
1401
1402
/// Constant state used during function compilation.
1403
pub struct EmitInfo {
1404
isa_flags: s390x_settings::Flags,
1405
}
1406
1407
impl EmitInfo {
1408
pub(crate) fn new(isa_flags: s390x_settings::Flags) -> Self {
1409
Self { isa_flags }
1410
}
1411
}
1412
1413
impl MachInstEmit for Inst {
1414
type State = EmitState;
1415
type Info = EmitInfo;
1416
1417
fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
1418
self.emit_with_alloc_consumer(sink, emit_info, state)
1419
}
1420
1421
fn pretty_print_inst(&self, state: &mut EmitState) -> String {
1422
self.print_with_state(state)
1423
}
1424
}
1425
1426
impl Inst {
1427
fn emit_with_alloc_consumer(
1428
&self,
1429
sink: &mut MachBuffer<Inst>,
1430
emit_info: &EmitInfo,
1431
state: &mut EmitState,
1432
) {
1433
// Verify that we can emit this Inst in the current ISA
1434
let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {
1435
match iset_requirement {
1436
// Baseline ISA is z14
1437
InstructionSet::Base => true,
1438
// Miscellaneous-Instruction-Extensions Facility 3 (z15)
1439
InstructionSet::MIE3 => emit_info.isa_flags.has_mie3(),
1440
// Vector-Enhancements Facility 2 (z15)
1441
InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),
1442
}
1443
};
1444
let isa_requirements = self.available_in_isa();
1445
if !matches_isa_flags(&isa_requirements) {
1446
panic!(
1447
"Cannot emit inst '{self:?}' for target; failed to match ISA requirements: {isa_requirements:?}"
1448
)
1449
}
1450
1451
match self {
1452
&Inst::AluRRR { alu_op, rd, rn, rm } => {
1453
let (opcode, have_rr) = match alu_op {
1454
ALUOp::Add32 => (0xb9f8, true), // ARK
1455
ALUOp::Add64 => (0xb9e8, true), // AGRK
1456
ALUOp::AddLogical32 => (0xb9fa, true), // ALRK
1457
ALUOp::AddLogical64 => (0xb9ea, true), // ALGRK
1458
ALUOp::Sub32 => (0xb9f9, true), // SRK
1459
ALUOp::Sub64 => (0xb9e9, true), // SGRK
1460
ALUOp::SubLogical32 => (0xb9fb, true), // SLRK
1461
ALUOp::SubLogical64 => (0xb9eb, true), // SLGRK
1462
ALUOp::Mul32 => (0xb9fd, true), // MSRKC
1463
ALUOp::Mul64 => (0xb9ed, true), // MSGRKC
1464
ALUOp::And32 => (0xb9f4, true), // NRK
1465
ALUOp::And64 => (0xb9e4, true), // NGRK
1466
ALUOp::Orr32 => (0xb9f6, true), // ORK
1467
ALUOp::Orr64 => (0xb9e6, true), // OGRK
1468
ALUOp::Xor32 => (0xb9f7, true), // XRK
1469
ALUOp::Xor64 => (0xb9e7, true), // XGRK
1470
ALUOp::NotAnd32 => (0xb974, false), // NNRK
1471
ALUOp::NotAnd64 => (0xb964, false), // NNGRK
1472
ALUOp::NotOrr32 => (0xb976, false), // NORK
1473
ALUOp::NotOrr64 => (0xb966, false), // NOGRK
1474
ALUOp::NotXor32 => (0xb977, false), // NXRK
1475
ALUOp::NotXor64 => (0xb967, false), // NXGRK
1476
ALUOp::AndNot32 => (0xb9f5, false), // NCRK
1477
ALUOp::AndNot64 => (0xb9e5, false), // NCGRK
1478
ALUOp::OrrNot32 => (0xb975, false), // OCRK
1479
ALUOp::OrrNot64 => (0xb965, false), // OCGRK
1480
_ => unreachable!(),
1481
};
1482
if have_rr && rd.to_reg() == rn {
1483
let inst = Inst::AluRR {
1484
alu_op,
1485
rd,
1486
ri: rn,
1487
rm,
1488
};
1489
inst.emit(sink, emit_info, state);
1490
} else {
1491
put(sink, &enc_rrf_ab(opcode, rd.to_reg(), rn, rm, 0));
1492
}
1493
}
1494
&Inst::AluRRSImm16 {
1495
alu_op,
1496
rd,
1497
rn,
1498
imm,
1499
} => {
1500
if rd.to_reg() == rn {
1501
let inst = Inst::AluRSImm16 {
1502
alu_op,
1503
rd,
1504
ri: rn,
1505
imm,
1506
};
1507
inst.emit(sink, emit_info, state);
1508
} else {
1509
let opcode = match alu_op {
1510
ALUOp::Add32 => 0xecd8, // AHIK
1511
ALUOp::Add64 => 0xecd9, // AGHIK
1512
_ => unreachable!(),
1513
};
1514
put(sink, &enc_rie_d(opcode, rd.to_reg(), rn, imm as u16));
1515
}
1516
}
1517
&Inst::AluRR { alu_op, rd, ri, rm } => {
1518
debug_assert_eq!(rd.to_reg(), ri);
1519
1520
let (opcode, is_rre) = match alu_op {
1521
ALUOp::Add32 => (0x1a, false), // AR
1522
ALUOp::Add64 => (0xb908, true), // AGR
1523
ALUOp::Add64Ext32 => (0xb918, true), // AGFR
1524
ALUOp::AddLogical32 => (0x1e, false), // ALR
1525
ALUOp::AddLogical64 => (0xb90a, true), // ALGR
1526
ALUOp::AddLogical64Ext32 => (0xb91a, true), // ALGFR
1527
ALUOp::Sub32 => (0x1b, false), // SR
1528
ALUOp::Sub64 => (0xb909, true), // SGR
1529
ALUOp::Sub64Ext32 => (0xb919, true), // SGFR
1530
ALUOp::SubLogical32 => (0x1f, false), // SLR
1531
ALUOp::SubLogical64 => (0xb90b, true), // SLGR
1532
ALUOp::SubLogical64Ext32 => (0xb91b, true), // SLGFR
1533
ALUOp::Mul32 => (0xb252, true), // MSR
1534
ALUOp::Mul64 => (0xb90c, true), // MSGR
1535
ALUOp::Mul64Ext32 => (0xb91c, true), // MSGFR
1536
ALUOp::And32 => (0x14, false), // NR
1537
ALUOp::And64 => (0xb980, true), // NGR
1538
ALUOp::Orr32 => (0x16, false), // OR
1539
ALUOp::Orr64 => (0xb981, true), // OGR
1540
ALUOp::Xor32 => (0x17, false), // XR
1541
ALUOp::Xor64 => (0xb982, true), // XGR
1542
_ => unreachable!(),
1543
};
1544
if is_rre {
1545
put(sink, &enc_rre(opcode, rd.to_reg(), rm));
1546
} else {
1547
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
1548
}
1549
}
1550
&Inst::AluRX {
1551
alu_op,
1552
rd,
1553
ri,
1554
ref mem,
1555
} => {
1556
debug_assert_eq!(rd.to_reg(), ri);
1557
let mem = mem.clone();
1558
1559
let (opcode_rx, opcode_rxy) = match alu_op {
1560
ALUOp::Add32 => (Some(0x5a), Some(0xe35a)), // A(Y)
1561
ALUOp::Add32Ext16 => (Some(0x4a), Some(0xe37a)), // AH(Y)
1562
ALUOp::Add64 => (None, Some(0xe308)), // AG
1563
ALUOp::Add64Ext16 => (None, Some(0xe338)), // AGH
1564
ALUOp::Add64Ext32 => (None, Some(0xe318)), // AGF
1565
ALUOp::AddLogical32 => (Some(0x5e), Some(0xe35e)), // AL(Y)
1566
ALUOp::AddLogical64 => (None, Some(0xe30a)), // ALG
1567
ALUOp::AddLogical64Ext32 => (None, Some(0xe31a)), // ALGF
1568
ALUOp::Sub32 => (Some(0x5b), Some(0xe35b)), // S(Y)
1569
ALUOp::Sub32Ext16 => (Some(0x4b), Some(0xe37b)), // SH(Y)
1570
ALUOp::Sub64 => (None, Some(0xe309)), // SG
1571
ALUOp::Sub64Ext16 => (None, Some(0xe339)), // SGH
1572
ALUOp::Sub64Ext32 => (None, Some(0xe319)), // SGF
1573
ALUOp::SubLogical32 => (Some(0x5f), Some(0xe35f)), // SL(Y)
1574
ALUOp::SubLogical64 => (None, Some(0xe30b)), // SLG
1575
ALUOp::SubLogical64Ext32 => (None, Some(0xe31b)), // SLGF
1576
ALUOp::Mul32 => (Some(0x71), Some(0xe351)), // MS(Y)
1577
ALUOp::Mul32Ext16 => (Some(0x4c), Some(0xe37c)), // MH(Y)
1578
ALUOp::Mul64 => (None, Some(0xe30c)), // MSG
1579
ALUOp::Mul64Ext16 => (None, Some(0xe33c)), // MSH
1580
ALUOp::Mul64Ext32 => (None, Some(0xe31c)), // MSGF
1581
ALUOp::And32 => (Some(0x54), Some(0xe354)), // N(Y)
1582
ALUOp::And64 => (None, Some(0xe380)), // NG
1583
ALUOp::Orr32 => (Some(0x56), Some(0xe356)), // O(Y)
1584
ALUOp::Orr64 => (None, Some(0xe381)), // OG
1585
ALUOp::Xor32 => (Some(0x57), Some(0xe357)), // X(Y)
1586
ALUOp::Xor64 => (None, Some(0xe382)), // XG
1587
_ => unreachable!(),
1588
};
1589
let rd = rd.to_reg();
1590
mem_emit(
1591
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
1592
);
1593
}
1594
&Inst::AluRSImm16 {
1595
alu_op,
1596
rd,
1597
ri,
1598
imm,
1599
} => {
1600
debug_assert_eq!(rd.to_reg(), ri);
1601
1602
let opcode = match alu_op {
1603
ALUOp::Add32 => 0xa7a, // AHI
1604
ALUOp::Add64 => 0xa7b, // AGHI
1605
ALUOp::Mul32 => 0xa7c, // MHI
1606
ALUOp::Mul64 => 0xa7d, // MGHI
1607
_ => unreachable!(),
1608
};
1609
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
1610
}
1611
&Inst::AluRSImm32 {
1612
alu_op,
1613
rd,
1614
ri,
1615
imm,
1616
} => {
1617
debug_assert_eq!(rd.to_reg(), ri);
1618
1619
let opcode = match alu_op {
1620
ALUOp::Add32 => 0xc29, // AFI
1621
ALUOp::Add64 => 0xc28, // AGFI
1622
ALUOp::Mul32 => 0xc21, // MSFI
1623
ALUOp::Mul64 => 0xc20, // MSGFI
1624
_ => unreachable!(),
1625
};
1626
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
1627
}
1628
&Inst::AluRUImm32 {
1629
alu_op,
1630
rd,
1631
ri,
1632
imm,
1633
} => {
1634
debug_assert_eq!(rd.to_reg(), ri);
1635
1636
let opcode = match alu_op {
1637
ALUOp::AddLogical32 => 0xc2b, // ALFI
1638
ALUOp::AddLogical64 => 0xc2a, // ALGFI
1639
ALUOp::SubLogical32 => 0xc25, // SLFI
1640
ALUOp::SubLogical64 => 0xc24, // SLGFI
1641
_ => unreachable!(),
1642
};
1643
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
1644
}
1645
&Inst::AluRUImm16Shifted {
1646
alu_op,
1647
rd,
1648
ri,
1649
imm,
1650
} => {
1651
debug_assert_eq!(rd.to_reg(), ri);
1652
1653
let opcode = match (alu_op, imm.shift) {
1654
(ALUOp::And32, 0) => 0xa57, // NILL
1655
(ALUOp::And32, 1) => 0xa56, // NILH
1656
(ALUOp::And64, 0) => 0xa57, // NILL
1657
(ALUOp::And64, 1) => 0xa56, // NILH
1658
(ALUOp::And64, 2) => 0xa55, // NIHL
1659
(ALUOp::And64, 3) => 0xa54, // NIHL
1660
(ALUOp::Orr32, 0) => 0xa5b, // OILL
1661
(ALUOp::Orr32, 1) => 0xa5a, // OILH
1662
(ALUOp::Orr64, 0) => 0xa5b, // OILL
1663
(ALUOp::Orr64, 1) => 0xa5a, // OILH
1664
(ALUOp::Orr64, 2) => 0xa59, // OIHL
1665
(ALUOp::Orr64, 3) => 0xa58, // OIHH
1666
_ => unreachable!(),
1667
};
1668
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
1669
}
1670
&Inst::AluRUImm32Shifted {
1671
alu_op,
1672
rd,
1673
ri,
1674
imm,
1675
} => {
1676
debug_assert_eq!(rd.to_reg(), ri);
1677
1678
let opcode = match (alu_op, imm.shift) {
1679
(ALUOp::And32, 0) => 0xc0b, // NILF
1680
(ALUOp::And64, 0) => 0xc0b, // NILF
1681
(ALUOp::And64, 1) => 0xc0a, // NIHF
1682
(ALUOp::Orr32, 0) => 0xc0d, // OILF
1683
(ALUOp::Orr64, 0) => 0xc0d, // OILF
1684
(ALUOp::Orr64, 1) => 0xc0c, // OILF
1685
(ALUOp::Xor32, 0) => 0xc07, // XILF
1686
(ALUOp::Xor64, 0) => 0xc07, // XILF
1687
(ALUOp::Xor64, 1) => 0xc06, // XILH
1688
_ => unreachable!(),
1689
};
1690
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
1691
}
1692
1693
&Inst::SMulWide { rd, rn, rm } => {
1694
let rd1 = rd.hi;
1695
let rd2 = rd.lo;
1696
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1697
1698
let opcode = 0xb9ec; // MGRK
1699
put(sink, &enc_rrf_ab(opcode, rd1.to_reg(), rn, rm, 0));
1700
}
1701
&Inst::UMulWide { rd, ri, rn } => {
1702
let rd1 = rd.hi;
1703
let rd2 = rd.lo;
1704
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1705
debug_assert_eq!(rd2.to_reg(), ri);
1706
1707
let opcode = 0xb986; // MLGR
1708
put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1709
}
1710
&Inst::SDivMod32 { rd, ri, rn } => {
1711
let rd1 = rd.hi;
1712
let rd2 = rd.lo;
1713
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1714
debug_assert_eq!(rd2.to_reg(), ri);
1715
1716
let opcode = 0xb91d; // DSGFR
1717
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1718
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1719
}
1720
&Inst::SDivMod64 { rd, ri, rn } => {
1721
let rd1 = rd.hi;
1722
let rd2 = rd.lo;
1723
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1724
debug_assert_eq!(rd2.to_reg(), ri);
1725
1726
let opcode = 0xb90d; // DSGR
1727
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1728
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1729
}
1730
&Inst::UDivMod32 { rd, ri, rn } => {
1731
let rd1 = rd.hi;
1732
let rd2 = rd.lo;
1733
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1734
let ri1 = ri.hi;
1735
let ri2 = ri.lo;
1736
debug_assert_eq!(rd1.to_reg(), ri1);
1737
debug_assert_eq!(rd2.to_reg(), ri2);
1738
1739
let opcode = 0xb997; // DLR
1740
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1741
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1742
}
1743
&Inst::UDivMod64 { rd, ri, rn } => {
1744
let rd1 = rd.hi;
1745
let rd2 = rd.lo;
1746
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1747
let ri1 = ri.hi;
1748
let ri2 = ri.lo;
1749
debug_assert_eq!(rd1.to_reg(), ri1);
1750
debug_assert_eq!(rd2.to_reg(), ri2);
1751
1752
let opcode = 0xb987; // DLGR
1753
let trap_code = TrapCode::INTEGER_DIVISION_BY_ZERO;
1754
put_with_trap(sink, &enc_rre(opcode, rd1.to_reg(), rn), trap_code);
1755
}
1756
&Inst::Flogr { rd, rn } => {
1757
let rd1 = rd.hi;
1758
let rd2 = rd.lo;
1759
debug_assert_valid_regpair!(rd1.to_reg(), rd2.to_reg());
1760
1761
let opcode = 0xb983; // FLOGR
1762
put(sink, &enc_rre(opcode, rd1.to_reg(), rn));
1763
}
1764
1765
&Inst::ShiftRR {
1766
shift_op,
1767
rd,
1768
rn,
1769
shift_imm,
1770
shift_reg,
1771
} => {
1772
let opcode = match shift_op {
1773
ShiftOp::RotL32 => 0xeb1d, // RLL
1774
ShiftOp::RotL64 => 0xeb1c, // RLLG
1775
ShiftOp::LShL32 => 0xebdf, // SLLK (SLL ?)
1776
ShiftOp::LShL64 => 0xeb0d, // SLLG
1777
ShiftOp::LShR32 => 0xebde, // SRLK (SRL ?)
1778
ShiftOp::LShR64 => 0xeb0c, // SRLG
1779
ShiftOp::AShR32 => 0xebdc, // SRAK (SRA ?)
1780
ShiftOp::AShR64 => 0xeb0a, // SRAG
1781
};
1782
put(
1783
sink,
1784
&enc_rsy(opcode, rd.to_reg(), rn, shift_reg, shift_imm.into()),
1785
);
1786
}
1787
1788
&Inst::RxSBG {
1789
op,
1790
rd,
1791
ri,
1792
rn,
1793
start_bit,
1794
end_bit,
1795
rotate_amt,
1796
} => {
1797
debug_assert_eq!(rd.to_reg(), ri);
1798
1799
let opcode = match op {
1800
RxSBGOp::Insert => 0xec59, // RISBGN
1801
RxSBGOp::And => 0xec54, // RNSBG
1802
RxSBGOp::Or => 0xec56, // ROSBG
1803
RxSBGOp::Xor => 0xec57, // RXSBG
1804
};
1805
put(
1806
sink,
1807
&enc_rie_f(
1808
opcode,
1809
rd.to_reg(),
1810
rn,
1811
start_bit,
1812
end_bit,
1813
(rotate_amt as u8) & 63,
1814
),
1815
);
1816
}
1817
1818
&Inst::RxSBGTest {
1819
op,
1820
rd,
1821
rn,
1822
start_bit,
1823
end_bit,
1824
rotate_amt,
1825
} => {
1826
let opcode = match op {
1827
RxSBGOp::And => 0xec54, // RNSBG
1828
RxSBGOp::Or => 0xec56, // ROSBG
1829
RxSBGOp::Xor => 0xec57, // RXSBG
1830
_ => unreachable!(),
1831
};
1832
put(
1833
sink,
1834
&enc_rie_f(
1835
opcode,
1836
rd,
1837
rn,
1838
start_bit | 0x80,
1839
end_bit,
1840
(rotate_amt as u8) & 63,
1841
),
1842
);
1843
}
1844
1845
&Inst::UnaryRR { op, rd, rn } => {
1846
match op {
1847
UnaryOp::Abs32 => {
1848
let opcode = 0x10; // LPR
1849
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1850
}
1851
UnaryOp::Abs64 => {
1852
let opcode = 0xb900; // LPGR
1853
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1854
}
1855
UnaryOp::Abs64Ext32 => {
1856
let opcode = 0xb910; // LPGFR
1857
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1858
}
1859
UnaryOp::Neg32 => {
1860
let opcode = 0x13; // LCR
1861
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
1862
}
1863
UnaryOp::Neg64 => {
1864
let opcode = 0xb903; // LCGR
1865
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1866
}
1867
UnaryOp::Neg64Ext32 => {
1868
let opcode = 0xb913; // LCGFR
1869
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1870
}
1871
UnaryOp::PopcntByte => {
1872
let opcode = 0xb9e1; // POPCNT
1873
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 0, 0));
1874
}
1875
UnaryOp::PopcntReg => {
1876
let opcode = 0xb9e1; // POPCNT
1877
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn, 8, 0));
1878
}
1879
UnaryOp::BSwap32 => {
1880
let opcode = 0xb91f; // LRVR
1881
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1882
}
1883
UnaryOp::BSwap64 => {
1884
let opcode = 0xb90f; // LRVRG
1885
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1886
}
1887
}
1888
}
1889
1890
&Inst::Extend {
1891
rd,
1892
rn,
1893
signed,
1894
from_bits,
1895
to_bits,
1896
} => {
1897
let opcode = match (signed, from_bits, to_bits) {
1898
(_, 1, 32) => 0xb926, // LBR
1899
(_, 1, 64) => 0xb906, // LGBR
1900
(false, 8, 32) => 0xb994, // LLCR
1901
(false, 8, 64) => 0xb984, // LLGCR
1902
(true, 8, 32) => 0xb926, // LBR
1903
(true, 8, 64) => 0xb906, // LGBR
1904
(false, 16, 32) => 0xb995, // LLHR
1905
(false, 16, 64) => 0xb985, // LLGHR
1906
(true, 16, 32) => 0xb927, // LHR
1907
(true, 16, 64) => 0xb907, // LGHR
1908
(false, 32, 64) => 0xb916, // LLGFR
1909
(true, 32, 64) => 0xb914, // LGFR
1910
_ => panic!(
1911
"Unsupported extend combination: signed = {signed}, from_bits = {from_bits}, to_bits = {to_bits}"
1912
),
1913
};
1914
put(sink, &enc_rre(opcode, rd.to_reg(), rn));
1915
}
1916
1917
&Inst::CmpRR { op, rn, rm } => {
1918
let (opcode, is_rre) = match op {
1919
CmpOp::CmpS32 => (0x19, false), // CR
1920
CmpOp::CmpS64 => (0xb920, true), // CGR
1921
CmpOp::CmpS64Ext32 => (0xb930, true), // CGFR
1922
CmpOp::CmpL32 => (0x15, false), // CLR
1923
CmpOp::CmpL64 => (0xb921, true), // CLGR
1924
CmpOp::CmpL64Ext32 => (0xb931, true), // CLGFR
1925
_ => unreachable!(),
1926
};
1927
if is_rre {
1928
put(sink, &enc_rre(opcode, rn, rm));
1929
} else {
1930
put(sink, &enc_rr(opcode, rn, rm));
1931
}
1932
}
1933
&Inst::CmpRX { op, rn, ref mem } => {
1934
let mem = mem.clone();
1935
1936
let (opcode_rx, opcode_rxy, opcode_ril) = match op {
1937
CmpOp::CmpS32 => (Some(0x59), Some(0xe359), Some(0xc6d)), // C(Y), CRL
1938
CmpOp::CmpS32Ext16 => (Some(0x49), Some(0xe379), Some(0xc65)), // CH(Y), CHRL
1939
CmpOp::CmpS64 => (None, Some(0xe320), Some(0xc68)), // CG, CGRL
1940
CmpOp::CmpS64Ext16 => (None, Some(0xe334), Some(0xc64)), // CGH, CGHRL
1941
CmpOp::CmpS64Ext32 => (None, Some(0xe330), Some(0xc6c)), // CGF, CGFRL
1942
CmpOp::CmpL32 => (Some(0x55), Some(0xe355), Some(0xc6f)), // CL(Y), CLRL
1943
CmpOp::CmpL32Ext16 => (None, None, Some(0xc67)), // CLHRL
1944
CmpOp::CmpL64 => (None, Some(0xe321), Some(0xc6a)), // CLG, CLGRL
1945
CmpOp::CmpL64Ext16 => (None, None, Some(0xc66)), // CLGHRL
1946
CmpOp::CmpL64Ext32 => (None, Some(0xe331), Some(0xc6e)), // CLGF, CLGFRL
1947
};
1948
mem_emit(
1949
rn, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
1950
);
1951
}
1952
&Inst::CmpRSImm16 { op, rn, imm } => {
1953
let opcode = match op {
1954
CmpOp::CmpS32 => 0xa7e, // CHI
1955
CmpOp::CmpS64 => 0xa7f, // CGHI
1956
_ => unreachable!(),
1957
};
1958
put(sink, &enc_ri_a(opcode, rn, imm as u16));
1959
}
1960
&Inst::CmpRSImm32 { op, rn, imm } => {
1961
let opcode = match op {
1962
CmpOp::CmpS32 => 0xc2d, // CFI
1963
CmpOp::CmpS64 => 0xc2c, // CGFI
1964
_ => unreachable!(),
1965
};
1966
put(sink, &enc_ril_a(opcode, rn, imm as u32));
1967
}
1968
&Inst::CmpRUImm32 { op, rn, imm } => {
1969
let opcode = match op {
1970
CmpOp::CmpL32 => 0xc2f, // CLFI
1971
CmpOp::CmpL64 => 0xc2e, // CLGFI
1972
_ => unreachable!(),
1973
};
1974
put(sink, &enc_ril_a(opcode, rn, imm));
1975
}
1976
&Inst::CmpTrapRR {
1977
op,
1978
rn,
1979
rm,
1980
cond,
1981
trap_code,
1982
} => {
1983
let opcode = match op {
1984
CmpOp::CmpS32 => 0xb972, // CRT
1985
CmpOp::CmpS64 => 0xb960, // CGRT
1986
CmpOp::CmpL32 => 0xb973, // CLRT
1987
CmpOp::CmpL64 => 0xb961, // CLGRT
1988
_ => unreachable!(),
1989
};
1990
put_with_trap(
1991
sink,
1992
&enc_rrf_cde(opcode, rn, rm, cond.bits(), 0),
1993
trap_code,
1994
);
1995
}
1996
&Inst::CmpTrapRSImm16 {
1997
op,
1998
rn,
1999
imm,
2000
cond,
2001
trap_code,
2002
} => {
2003
let opcode = match op {
2004
CmpOp::CmpS32 => 0xec72, // CIT
2005
CmpOp::CmpS64 => 0xec70, // CGIT
2006
_ => unreachable!(),
2007
};
2008
put_with_trap(
2009
sink,
2010
&enc_rie_a(opcode, rn, imm as u16, cond.bits()),
2011
trap_code,
2012
);
2013
}
2014
&Inst::CmpTrapRUImm16 {
2015
op,
2016
rn,
2017
imm,
2018
cond,
2019
trap_code,
2020
} => {
2021
let opcode = match op {
2022
CmpOp::CmpL32 => 0xec73, // CLFIT
2023
CmpOp::CmpL64 => 0xec71, // CLGIT
2024
_ => unreachable!(),
2025
};
2026
put_with_trap(sink, &enc_rie_a(opcode, rn, imm, cond.bits()), trap_code);
2027
}
2028
2029
&Inst::AtomicRmw {
2030
alu_op,
2031
rd,
2032
rn,
2033
ref mem,
2034
} => {
2035
let mem = mem.clone();
2036
2037
let opcode = match alu_op {
2038
ALUOp::Add32 => 0xebf8, // LAA
2039
ALUOp::Add64 => 0xebe8, // LAAG
2040
ALUOp::AddLogical32 => 0xebfa, // LAAL
2041
ALUOp::AddLogical64 => 0xebea, // LAALG
2042
ALUOp::And32 => 0xebf4, // LAN
2043
ALUOp::And64 => 0xebe4, // LANG
2044
ALUOp::Orr32 => 0xebf6, // LAO
2045
ALUOp::Orr64 => 0xebe6, // LAOG
2046
ALUOp::Xor32 => 0xebf7, // LAX
2047
ALUOp::Xor64 => 0xebe7, // LAXG
2048
_ => unreachable!(),
2049
};
2050
2051
let rd = rd.to_reg();
2052
mem_rs_emit(
2053
rd,
2054
rn,
2055
&mem,
2056
None,
2057
Some(opcode),
2058
true,
2059
sink,
2060
emit_info,
2061
state,
2062
);
2063
}
2064
&Inst::Loop { ref body, cond } => {
2065
// This sequence is *one* instruction in the vcode, and is expanded only here at
2066
// emission time, because it requires branching to internal labels.
2067
let loop_label = sink.get_label();
2068
let done_label = sink.get_label();
2069
2070
// Emit label at the start of the loop.
2071
sink.bind_label(loop_label, &mut state.ctrl_plane);
2072
2073
for inst in (&body).into_iter() {
2074
match &inst {
2075
// Replace a CondBreak with a branch to done_label.
2076
&Inst::CondBreak { cond } => {
2077
let opcode = 0xc04; // BCRL
2078
sink.use_label_at_offset(
2079
sink.cur_offset(),
2080
done_label,
2081
LabelUse::BranchRIL,
2082
);
2083
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2084
}
2085
_ => inst.emit_with_alloc_consumer(sink, emit_info, state),
2086
};
2087
}
2088
2089
let opcode = 0xc04; // BCRL
2090
sink.use_label_at_offset(sink.cur_offset(), loop_label, LabelUse::BranchRIL);
2091
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
2092
2093
// Emit label at the end of the loop.
2094
sink.bind_label(done_label, &mut state.ctrl_plane);
2095
}
2096
&Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.
2097
&Inst::AtomicCas32 {
2098
rd,
2099
ri,
2100
rn,
2101
ref mem,
2102
}
2103
| &Inst::AtomicCas64 {
2104
rd,
2105
ri,
2106
rn,
2107
ref mem,
2108
} => {
2109
debug_assert_eq!(rd.to_reg(), ri);
2110
let mem = mem.clone();
2111
2112
let (opcode_rs, opcode_rsy) = match self {
2113
&Inst::AtomicCas32 { .. } => (Some(0xba), Some(0xeb14)), // CS(Y)
2114
&Inst::AtomicCas64 { .. } => (None, Some(0xeb30)), // CSG
2115
_ => unreachable!(),
2116
};
2117
2118
let rd = rd.to_reg();
2119
mem_rs_emit(
2120
rd, rn, &mem, opcode_rs, opcode_rsy, true, sink, emit_info, state,
2121
);
2122
}
2123
&Inst::Fence => {
2124
put(sink, &enc_e(0x07e0));
2125
}
2126
2127
&Inst::Load32 { rd, ref mem }
2128
| &Inst::Load32ZExt8 { rd, ref mem }
2129
| &Inst::Load32SExt8 { rd, ref mem }
2130
| &Inst::Load32ZExt16 { rd, ref mem }
2131
| &Inst::Load32SExt16 { rd, ref mem }
2132
| &Inst::Load64 { rd, ref mem }
2133
| &Inst::Load64ZExt8 { rd, ref mem }
2134
| &Inst::Load64SExt8 { rd, ref mem }
2135
| &Inst::Load64ZExt16 { rd, ref mem }
2136
| &Inst::Load64SExt16 { rd, ref mem }
2137
| &Inst::Load64ZExt32 { rd, ref mem }
2138
| &Inst::Load64SExt32 { rd, ref mem }
2139
| &Inst::LoadRev16 { rd, ref mem }
2140
| &Inst::LoadRev32 { rd, ref mem }
2141
| &Inst::LoadRev64 { rd, ref mem } => {
2142
let mem = mem.clone();
2143
2144
let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2145
&Inst::Load32 { .. } => (Some(0x58), Some(0xe358), Some(0xc4d)), // L(Y), LRL
2146
&Inst::Load32ZExt8 { .. } => (None, Some(0xe394), None), // LLC
2147
&Inst::Load32SExt8 { .. } => (None, Some(0xe376), None), // LB
2148
&Inst::Load32ZExt16 { .. } => (None, Some(0xe395), Some(0xc42)), // LLH, LLHRL
2149
&Inst::Load32SExt16 { .. } => (Some(0x48), Some(0xe378), Some(0xc45)), // LH(Y), LHRL
2150
&Inst::Load64 { .. } => (None, Some(0xe304), Some(0xc48)), // LG, LGRL
2151
&Inst::Load64ZExt8 { .. } => (None, Some(0xe390), None), // LLGC
2152
&Inst::Load64SExt8 { .. } => (None, Some(0xe377), None), // LGB
2153
&Inst::Load64ZExt16 { .. } => (None, Some(0xe391), Some(0xc46)), // LLGH, LLGHRL
2154
&Inst::Load64SExt16 { .. } => (None, Some(0xe315), Some(0xc44)), // LGH, LGHRL
2155
&Inst::Load64ZExt32 { .. } => (None, Some(0xe316), Some(0xc4e)), // LLGF, LLGFRL
2156
&Inst::Load64SExt32 { .. } => (None, Some(0xe314), Some(0xc4c)), // LGF, LGFRL
2157
&Inst::LoadRev16 { .. } => (None, Some(0xe31f), None), // LRVH
2158
&Inst::LoadRev32 { .. } => (None, Some(0xe31e), None), // LRV
2159
&Inst::LoadRev64 { .. } => (None, Some(0xe30f), None), // LRVG
2160
_ => unreachable!(),
2161
};
2162
let rd = rd.to_reg();
2163
mem_emit(
2164
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2165
);
2166
}
2167
2168
&Inst::Store8 { rd, ref mem }
2169
| &Inst::Store16 { rd, ref mem }
2170
| &Inst::Store32 { rd, ref mem }
2171
| &Inst::Store64 { rd, ref mem }
2172
| &Inst::StoreRev16 { rd, ref mem }
2173
| &Inst::StoreRev32 { rd, ref mem }
2174
| &Inst::StoreRev64 { rd, ref mem } => {
2175
let mem = mem.clone();
2176
2177
let (opcode_rx, opcode_rxy, opcode_ril) = match self {
2178
&Inst::Store8 { .. } => (Some(0x42), Some(0xe372), None), // STC(Y)
2179
&Inst::Store16 { .. } => (Some(0x40), Some(0xe370), Some(0xc47)), // STH(Y), STHRL
2180
&Inst::Store32 { .. } => (Some(0x50), Some(0xe350), Some(0xc4f)), // ST(Y), STRL
2181
&Inst::Store64 { .. } => (None, Some(0xe324), Some(0xc4b)), // STG, STGRL
2182
&Inst::StoreRev16 { .. } => (None, Some(0xe33f), None), // STRVH
2183
&Inst::StoreRev32 { .. } => (None, Some(0xe33e), None), // STRV
2184
&Inst::StoreRev64 { .. } => (None, Some(0xe32f), None), // STRVG
2185
_ => unreachable!(),
2186
};
2187
mem_emit(
2188
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, true, sink, emit_info, state,
2189
);
2190
}
2191
&Inst::StoreImm8 { imm, ref mem } => {
2192
let mem = mem.clone();
2193
2194
let opcode_si = 0x92; // MVI
2195
let opcode_siy = 0xeb52; // MVIY
2196
mem_imm8_emit(
2197
imm, &mem, opcode_si, opcode_siy, true, sink, emit_info, state,
2198
);
2199
}
2200
&Inst::StoreImm16 { imm, ref mem }
2201
| &Inst::StoreImm32SExt16 { imm, ref mem }
2202
| &Inst::StoreImm64SExt16 { imm, ref mem } => {
2203
let mem = mem.clone();
2204
2205
let opcode = match self {
2206
&Inst::StoreImm16 { .. } => 0xe544, // MVHHI
2207
&Inst::StoreImm32SExt16 { .. } => 0xe54c, // MVHI
2208
&Inst::StoreImm64SExt16 { .. } => 0xe548, // MVGHI
2209
_ => unreachable!(),
2210
};
2211
mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);
2212
}
2213
2214
&Inst::LoadMultiple64 { rt, rt2, ref mem } => {
2215
let mem = mem.clone();
2216
2217
let opcode = 0xeb04; // LMG
2218
let rt = rt.to_reg();
2219
let rt2 = rt2.to_reg();
2220
mem_rs_emit(
2221
rt,
2222
rt2,
2223
&mem,
2224
None,
2225
Some(opcode),
2226
true,
2227
sink,
2228
emit_info,
2229
state,
2230
);
2231
}
2232
&Inst::StoreMultiple64 { rt, rt2, ref mem } => {
2233
let mem = mem.clone();
2234
2235
let opcode = 0xeb24; // STMG
2236
mem_rs_emit(
2237
rt,
2238
rt2,
2239
&mem,
2240
None,
2241
Some(opcode),
2242
true,
2243
sink,
2244
emit_info,
2245
state,
2246
);
2247
}
2248
2249
&Inst::LoadAddr { rd, ref mem } => {
2250
let mem = mem.clone();
2251
2252
let opcode_rx = Some(0x41); // LA
2253
let opcode_rxy = Some(0xe371); // LAY
2254
let opcode_ril = Some(0xc00); // LARL
2255
let rd = rd.to_reg();
2256
mem_emit(
2257
rd, &mem, opcode_rx, opcode_rxy, opcode_ril, false, sink, emit_info, state,
2258
);
2259
}
2260
2261
&Inst::Mov64 { rd, rm } => {
2262
let opcode = 0xb904; // LGR
2263
put(sink, &enc_rre(opcode, rd.to_reg(), rm));
2264
}
2265
&Inst::MovPReg { rd, rm } => {
2266
Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);
2267
}
2268
&Inst::Mov32 { rd, rm } => {
2269
let opcode = 0x18; // LR
2270
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2271
}
2272
&Inst::Mov32Imm { rd, imm } => {
2273
let opcode = 0xc09; // IILF
2274
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm));
2275
}
2276
&Inst::Mov32SImm16 { rd, imm } => {
2277
let opcode = 0xa78; // LHI
2278
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2279
}
2280
&Inst::Mov64SImm16 { rd, imm } => {
2281
let opcode = 0xa79; // LGHI
2282
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm as u16));
2283
}
2284
&Inst::Mov64SImm32 { rd, imm } => {
2285
let opcode = 0xc01; // LGFI
2286
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm as u32));
2287
}
2288
&Inst::CMov32 { rd, cond, ri, rm } => {
2289
debug_assert_eq!(rd.to_reg(), ri);
2290
2291
let opcode = 0xb9f2; // LOCR
2292
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2293
}
2294
&Inst::CMov64 { rd, cond, ri, rm } => {
2295
debug_assert_eq!(rd.to_reg(), ri);
2296
2297
let opcode = 0xb9e2; // LOCGR
2298
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rm, cond.bits(), 0));
2299
}
2300
&Inst::CMov32SImm16 { rd, cond, ri, imm } => {
2301
debug_assert_eq!(rd.to_reg(), ri);
2302
2303
let opcode = 0xec42; // LOCHI
2304
put(
2305
sink,
2306
&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2307
);
2308
}
2309
&Inst::CMov64SImm16 { rd, cond, ri, imm } => {
2310
debug_assert_eq!(rd.to_reg(), ri);
2311
2312
let opcode = 0xec46; // LOCGHI
2313
put(
2314
sink,
2315
&enc_rie_g(opcode, rd.to_reg(), imm as u16, cond.bits()),
2316
);
2317
}
2318
&Inst::Mov64UImm16Shifted { rd, imm } => {
2319
let opcode = match imm.shift {
2320
0 => 0xa5f, // LLILL
2321
1 => 0xa5e, // LLILH
2322
2 => 0xa5d, // LLIHL
2323
3 => 0xa5c, // LLIHH
2324
_ => unreachable!(),
2325
};
2326
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2327
}
2328
&Inst::Mov64UImm32Shifted { rd, imm } => {
2329
let opcode = match imm.shift {
2330
0 => 0xc0f, // LLILF
2331
1 => 0xc0e, // LLIHF
2332
_ => unreachable!(),
2333
};
2334
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2335
}
2336
&Inst::Insert64UImm16Shifted { rd, ri, imm } => {
2337
debug_assert_eq!(rd.to_reg(), ri);
2338
2339
let opcode = match imm.shift {
2340
0 => 0xa53, // IILL
2341
1 => 0xa52, // IILH
2342
2 => 0xa51, // IIHL
2343
3 => 0xa50, // IIHH
2344
_ => unreachable!(),
2345
};
2346
put(sink, &enc_ri_a(opcode, rd.to_reg(), imm.bits));
2347
}
2348
&Inst::Insert64UImm32Shifted { rd, ri, imm } => {
2349
debug_assert_eq!(rd.to_reg(), ri);
2350
2351
let opcode = match imm.shift {
2352
0 => 0xc09, // IILF
2353
1 => 0xc08, // IIHF
2354
_ => unreachable!(),
2355
};
2356
put(sink, &enc_ril_a(opcode, rd.to_reg(), imm.bits));
2357
}
2358
&Inst::LoadAR { rd, ar } => {
2359
let opcode = 0xb24f; // EAR
2360
put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2361
}
2362
2363
&Inst::InsertAR { rd, ri, ar } => {
2364
debug_assert_eq!(rd.to_reg(), ri);
2365
2366
let opcode = 0xb24f; // EAR
2367
put(sink, &enc_rre(opcode, rd.to_reg(), gpr(ar)));
2368
}
2369
&Inst::LoadSymbolReloc {
2370
rd,
2371
ref symbol_reloc,
2372
} => {
2373
let reg = writable_spilltmp_reg().to_reg();
2374
put(sink, &enc_ri_b(OPCODE_BRAS, reg, 12));
2375
let (reloc, name, offset) = match &**symbol_reloc {
2376
SymbolReloc::Absolute { name, offset } => (Reloc::Abs8, name, *offset),
2377
SymbolReloc::TlsGd { name } => (Reloc::S390xTlsGd64, name, 0),
2378
};
2379
sink.add_reloc(reloc, name, offset);
2380
sink.put8(0);
2381
let inst = Inst::Load64 {
2382
rd,
2383
mem: MemArg::reg(reg, MemFlags::trusted()),
2384
};
2385
inst.emit(sink, emit_info, state);
2386
}
2387
2388
&Inst::FpuMove32 { rd, rn } => {
2389
if is_fpr(rd.to_reg()) && is_fpr(rn) {
2390
let opcode = 0x38; // LER
2391
put(sink, &enc_rr(opcode, rd.to_reg(), rn));
2392
} else {
2393
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
2394
}
2395
}
2396
&Inst::FpuMove64 { rd, rn } => {
2397
if is_fpr(rd.to_reg()) && is_fpr(rn) {
2398
put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rn));
2399
} else {
2400
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
2401
}
2402
}
2403
&Inst::FpuCMov32 { rd, cond, ri, rm } => {
2404
debug_assert_eq!(rd.to_reg(), ri);
2405
2406
if is_fpr(rd.to_reg()) && is_fpr(rm) {
2407
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));
2408
let opcode = 0x38; // LER
2409
put(sink, &enc_rr(opcode, rd.to_reg(), rm));
2410
} else {
2411
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
2412
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
2413
}
2414
}
2415
&Inst::FpuCMov64 { rd, cond, ri, rm } => {
2416
debug_assert_eq!(rd.to_reg(), ri);
2417
2418
if is_fpr(rd.to_reg()) && is_fpr(rm) {
2419
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 2));
2420
put(sink, &enc_rr(OPCODE_LDR, rd.to_reg(), rm));
2421
} else {
2422
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
2423
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
2424
}
2425
}
2426
&Inst::FpuRR { fpu_op, rd, rn } => {
2427
let (opcode, m3, m4, m5, opcode_fpr) = match fpu_op {
2428
FPUOp1::Abs32 => (0xe7cc, 2, 8, 2, Some(0xb300)), // WFPSO, LPEBR
2429
FPUOp1::Abs64 => (0xe7cc, 3, 8, 2, Some(0xb310)), // WFPSO, LPDBR
2430
FPUOp1::Abs128 => (0xe7cc, 4, 8, 2, None), // WFPSO
2431
FPUOp1::Abs32x4 => (0xe7cc, 2, 0, 2, None), // VFPSO
2432
FPUOp1::Abs64x2 => (0xe7cc, 3, 0, 2, None), // VFPSO
2433
FPUOp1::Neg32 => (0xe7cc, 2, 8, 0, Some(0xb303)), // WFPSO, LCEBR
2434
FPUOp1::Neg64 => (0xe7cc, 3, 8, 0, Some(0xb313)), // WFPSO, LCDBR
2435
FPUOp1::Neg128 => (0xe7cc, 4, 8, 0, None), // WFPSO
2436
FPUOp1::Neg32x4 => (0xe7cc, 2, 0, 0, None), // VFPSO
2437
FPUOp1::Neg64x2 => (0xe7cc, 3, 0, 0, None), // VFPSO
2438
FPUOp1::NegAbs32 => (0xe7cc, 2, 8, 1, Some(0xb301)), // WFPSO, LNEBR
2439
FPUOp1::NegAbs64 => (0xe7cc, 3, 8, 1, Some(0xb311)), // WFPSO, LNDBR
2440
FPUOp1::NegAbs128 => (0xe7cc, 4, 8, 1, None), // WFPSO
2441
FPUOp1::NegAbs32x4 => (0xe7cc, 2, 0, 1, None), // VFPSO
2442
FPUOp1::NegAbs64x2 => (0xe7cc, 3, 0, 1, None), // VFPSO
2443
FPUOp1::Sqrt32 => (0xe7ce, 2, 8, 0, Some(0xb314)), // WFSQ, SQEBR
2444
FPUOp1::Sqrt64 => (0xe7ce, 3, 8, 0, Some(0xb315)), // WFSQ, SQDBR
2445
FPUOp1::Sqrt128 => (0xe7ce, 4, 8, 0, None), // WFSQ
2446
FPUOp1::Sqrt32x4 => (0xe7ce, 2, 0, 0, None), // VFSQ
2447
FPUOp1::Sqrt64x2 => (0xe7ce, 3, 0, 0, None), // VFSQ
2448
FPUOp1::Cvt32To64 => (0xe7c4, 2, 8, 0, Some(0xb304)), // WFLL, LDEBR
2449
FPUOp1::Cvt32x4To64x2 => (0xe7c4, 2, 0, 0, None), // VFLL
2450
FPUOp1::Cvt64To128 => (0xe7c4, 3, 8, 0, None), // WFLL
2451
};
2452
if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {
2453
put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rn));
2454
} else {
2455
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, m5));
2456
}
2457
}
2458
&Inst::FpuRRR { fpu_op, rd, rn, rm } => {
2459
let (opcode, m4, m5, m6, opcode_fpr) = match fpu_op {
2460
FPUOp2::Add32 => (0xe7e3, 2, 8, 0, Some(0xb30a)), // WFA, AEBR
2461
FPUOp2::Add64 => (0xe7e3, 3, 8, 0, Some(0xb31a)), // WFA, ADBR
2462
FPUOp2::Add128 => (0xe7e3, 4, 8, 0, None), // WFA
2463
FPUOp2::Add32x4 => (0xe7e3, 2, 0, 0, None), // VFA
2464
FPUOp2::Add64x2 => (0xe7e3, 3, 0, 0, None), // VFA
2465
FPUOp2::Sub32 => (0xe7e2, 2, 8, 0, Some(0xb30b)), // WFS, SEBR
2466
FPUOp2::Sub64 => (0xe7e2, 3, 8, 0, Some(0xb31b)), // WFS, SDBR
2467
FPUOp2::Sub128 => (0xe7e2, 4, 8, 0, None), // WFS
2468
FPUOp2::Sub32x4 => (0xe7e2, 2, 0, 0, None), // VFS
2469
FPUOp2::Sub64x2 => (0xe7e2, 3, 0, 0, None), // VFS
2470
FPUOp2::Mul32 => (0xe7e7, 2, 8, 0, Some(0xb317)), // WFM, MEEBR
2471
FPUOp2::Mul64 => (0xe7e7, 3, 8, 0, Some(0xb31c)), // WFM, MDBR
2472
FPUOp2::Mul128 => (0xe7e7, 4, 8, 0, None), // WFM
2473
FPUOp2::Mul32x4 => (0xe7e7, 2, 0, 0, None), // VFM
2474
FPUOp2::Mul64x2 => (0xe7e7, 3, 0, 0, None), // VFM
2475
FPUOp2::Div32 => (0xe7e5, 2, 8, 0, Some(0xb30d)), // WFD, DEBR
2476
FPUOp2::Div64 => (0xe7e5, 3, 8, 0, Some(0xb31d)), // WFD, DDBR
2477
FPUOp2::Div128 => (0xe7e5, 4, 8, 0, None), // WFD
2478
FPUOp2::Div32x4 => (0xe7e5, 2, 0, 0, None), // VFD
2479
FPUOp2::Div64x2 => (0xe7e5, 3, 0, 0, None), // VFD
2480
FPUOp2::Max32 => (0xe7ef, 2, 8, 1, None), // WFMAX
2481
FPUOp2::Max64 => (0xe7ef, 3, 8, 1, None), // WFMAX
2482
FPUOp2::Max128 => (0xe7ef, 4, 8, 1, None), // WFMAX
2483
FPUOp2::Max32x4 => (0xe7ef, 2, 0, 1, None), // VFMAX
2484
FPUOp2::Max64x2 => (0xe7ef, 3, 0, 1, None), // VFMAX
2485
FPUOp2::Min32 => (0xe7ee, 2, 8, 1, None), // WFMIN
2486
FPUOp2::Min64 => (0xe7ee, 3, 8, 1, None), // WFMIN
2487
FPUOp2::Min128 => (0xe7ee, 4, 8, 1, None), // WFMIN
2488
FPUOp2::Min32x4 => (0xe7ee, 2, 0, 1, None), // VFMIN
2489
FPUOp2::Min64x2 => (0xe7ee, 3, 0, 1, None), // VFMIN
2490
FPUOp2::MaxPseudo32 => (0xe7ef, 2, 8, 3, None), // WFMAX
2491
FPUOp2::MaxPseudo64 => (0xe7ef, 3, 8, 3, None), // WFMAX
2492
FPUOp2::MaxPseudo128 => (0xe7ef, 4, 8, 3, None), // WFMAX
2493
FPUOp2::MaxPseudo32x4 => (0xe7ef, 2, 0, 3, None), // VFMAX
2494
FPUOp2::MaxPseudo64x2 => (0xe7ef, 3, 0, 3, None), // VFMAX
2495
FPUOp2::MinPseudo32 => (0xe7ee, 2, 8, 3, None), // WFMIN
2496
FPUOp2::MinPseudo64 => (0xe7ee, 3, 8, 3, None), // WFMIN
2497
FPUOp2::MinPseudo128 => (0xe7ee, 4, 8, 3, None), // WFMIN
2498
FPUOp2::MinPseudo32x4 => (0xe7ee, 2, 0, 3, None), // VFMIN
2499
FPUOp2::MinPseudo64x2 => (0xe7ee, 3, 0, 3, None), // VFMIN
2500
};
2501
if m5 == 8 && opcode_fpr.is_some() && rd.to_reg() == rn && is_fpr(rn) && is_fpr(rm)
2502
{
2503
put(sink, &enc_rre(opcode_fpr.unwrap(), rd.to_reg(), rm));
2504
} else {
2505
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, m5, m6));
2506
}
2507
}
2508
&Inst::FpuRRRR {
2509
fpu_op,
2510
rd,
2511
rn,
2512
rm,
2513
ra,
2514
} => {
2515
let (opcode, m5, m6, opcode_fpr) = match fpu_op {
2516
FPUOp3::MAdd32 => (0xe78f, 8, 2, Some(0xb30e)), // WFMA, MAEBR
2517
FPUOp3::MAdd64 => (0xe78f, 8, 3, Some(0xb31e)), // WFMA, MADBR
2518
FPUOp3::MAdd128 => (0xe78f, 8, 4, None), // WFMA
2519
FPUOp3::MAdd32x4 => (0xe78f, 0, 2, None), // VFMA
2520
FPUOp3::MAdd64x2 => (0xe78f, 0, 3, None), // VFMA
2521
FPUOp3::MSub32 => (0xe78e, 8, 2, Some(0xb30f)), // WFMS, MSEBR
2522
FPUOp3::MSub64 => (0xe78e, 8, 3, Some(0xb31f)), // WFMS, MSDBR
2523
FPUOp3::MSub128 => (0xe78e, 8, 4, None), // WFMS
2524
FPUOp3::MSub32x4 => (0xe78e, 0, 2, None), // VFMS
2525
FPUOp3::MSub64x2 => (0xe78e, 0, 3, None), // VFMS
2526
};
2527
if m5 == 8
2528
&& opcode_fpr.is_some()
2529
&& rd.to_reg() == ra
2530
&& is_fpr(rn)
2531
&& is_fpr(rm)
2532
&& is_fpr(ra)
2533
{
2534
put(sink, &enc_rrd(opcode_fpr.unwrap(), rd.to_reg(), rm, rn));
2535
} else {
2536
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, m5, m6));
2537
}
2538
}
2539
&Inst::FpuRound { op, mode, rd, rn } => {
2540
let mode = match mode {
2541
FpuRoundMode::Current => 0,
2542
FpuRoundMode::ToNearest => 1,
2543
FpuRoundMode::ShorterPrecision => 3,
2544
FpuRoundMode::ToNearestTiesToEven => 4,
2545
FpuRoundMode::ToZero => 5,
2546
FpuRoundMode::ToPosInfinity => 6,
2547
FpuRoundMode::ToNegInfinity => 7,
2548
};
2549
let (opcode, m3, m4, opcode_fpr) = match op {
2550
FpuRoundOp::Cvt64To32 => (0xe7c5, 3, 8, Some(0xb344)), // WFLR, LEDBR(A)
2551
FpuRoundOp::Cvt64x2To32x4 => (0xe7c5, 3, 0, None), // VFLR
2552
FpuRoundOp::Cvt128To64 => (0xe7c5, 4, 8, None), // WFLR
2553
FpuRoundOp::Round32 => (0xe7c7, 2, 8, Some(0xb357)), // WFI, FIEBR
2554
FpuRoundOp::Round64 => (0xe7c7, 3, 8, Some(0xb35f)), // WFI, FIDBR
2555
FpuRoundOp::Round128 => (0xe7c7, 4, 8, None), // WFI
2556
FpuRoundOp::Round32x4 => (0xe7c7, 2, 0, None), // VFI
2557
FpuRoundOp::Round64x2 => (0xe7c7, 3, 0, None), // VFI
2558
FpuRoundOp::ToSInt32 => (0xe7c2, 2, 8, None), // WCSFP
2559
FpuRoundOp::ToSInt64 => (0xe7c2, 3, 8, None), // WCSFP
2560
FpuRoundOp::ToUInt32 => (0xe7c0, 2, 8, None), // WCLFP
2561
FpuRoundOp::ToUInt64 => (0xe7c0, 3, 8, None), // WCLFP
2562
FpuRoundOp::ToSInt32x4 => (0xe7c2, 2, 0, None), // VCSFP
2563
FpuRoundOp::ToSInt64x2 => (0xe7c2, 3, 0, None), // VCSFP
2564
FpuRoundOp::ToUInt32x4 => (0xe7c0, 2, 0, None), // VCLFP
2565
FpuRoundOp::ToUInt64x2 => (0xe7c0, 3, 0, None), // VCLFP
2566
FpuRoundOp::FromSInt32 => (0xe7c3, 2, 8, None), // WCFPS
2567
FpuRoundOp::FromSInt64 => (0xe7c3, 3, 8, None), // WCFPS
2568
FpuRoundOp::FromUInt32 => (0xe7c1, 2, 8, None), // WCFPL
2569
FpuRoundOp::FromUInt64 => (0xe7c1, 3, 8, None), // WCFPL
2570
FpuRoundOp::FromSInt32x4 => (0xe7c3, 2, 0, None), // VCFPS
2571
FpuRoundOp::FromSInt64x2 => (0xe7c3, 3, 0, None), // VCFPS
2572
FpuRoundOp::FromUInt32x4 => (0xe7c1, 2, 0, None), // VCFPL
2573
FpuRoundOp::FromUInt64x2 => (0xe7c1, 3, 0, None), // VCFPL
2574
};
2575
if m4 == 8 && opcode_fpr.is_some() && is_fpr(rd.to_reg()) && is_fpr(rn) {
2576
put(
2577
sink,
2578
&enc_rrf_cde(opcode_fpr.unwrap(), rd.to_reg(), rn, mode, 0),
2579
);
2580
} else {
2581
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, m4, mode));
2582
}
2583
}
2584
&Inst::FpuConv128FromInt { op, mode, rd, rn } => {
2585
let rd1 = rd.hi;
2586
let rd2 = rd.lo;
2587
debug_assert_valid_fp_regpair!(rd1.to_reg(), rd2.to_reg());
2588
2589
let mode = match mode {
2590
FpuRoundMode::Current => 0,
2591
FpuRoundMode::ToNearest => 1,
2592
FpuRoundMode::ShorterPrecision => 3,
2593
FpuRoundMode::ToNearestTiesToEven => 4,
2594
FpuRoundMode::ToZero => 5,
2595
FpuRoundMode::ToPosInfinity => 6,
2596
FpuRoundMode::ToNegInfinity => 7,
2597
};
2598
let opcode = match op {
2599
FpuConv128Op::SInt32 => 0xb396, // CXFBRA
2600
FpuConv128Op::SInt64 => 0xb3a6, // CXGBRA
2601
FpuConv128Op::UInt32 => 0xb392, // CXLFBR
2602
FpuConv128Op::UInt64 => 0xb3a2, // CXLGBR
2603
};
2604
put(sink, &enc_rrf_cde(opcode, rd1.to_reg(), rn, mode, 0));
2605
}
2606
&Inst::FpuConv128ToInt { op, mode, rd, rn } => {
2607
let rn1 = rn.hi;
2608
let rn2 = rn.lo;
2609
debug_assert_valid_fp_regpair!(rn1, rn2);
2610
2611
let mode = match mode {
2612
FpuRoundMode::Current => 0,
2613
FpuRoundMode::ToNearest => 1,
2614
FpuRoundMode::ShorterPrecision => 3,
2615
FpuRoundMode::ToNearestTiesToEven => 4,
2616
FpuRoundMode::ToZero => 5,
2617
FpuRoundMode::ToPosInfinity => 6,
2618
FpuRoundMode::ToNegInfinity => 7,
2619
};
2620
let opcode = match op {
2621
FpuConv128Op::SInt32 => 0xb39a, // CFXBRA
2622
FpuConv128Op::SInt64 => 0xb3aa, // CGXBRA
2623
FpuConv128Op::UInt32 => 0xb39e, // CLFXBR
2624
FpuConv128Op::UInt64 => 0xb3ae, // CLGXBR
2625
};
2626
put(sink, &enc_rrf_cde(opcode, rd.to_reg(), rn1, mode, 0));
2627
}
2628
&Inst::FpuCmp32 { rn, rm } => {
2629
if is_fpr(rn) && is_fpr(rm) {
2630
let opcode = 0xb309; // CEBR
2631
put(sink, &enc_rre(opcode, rn, rm));
2632
} else {
2633
let opcode = 0xe7cb; // WFC
2634
put(sink, &enc_vrr_a(opcode, rn, rm, 2, 0, 0));
2635
}
2636
}
2637
&Inst::FpuCmp64 { rn, rm } => {
2638
if is_fpr(rn) && is_fpr(rm) {
2639
let opcode = 0xb319; // CDBR
2640
put(sink, &enc_rre(opcode, rn, rm));
2641
} else {
2642
let opcode = 0xe7cb; // WFC
2643
put(sink, &enc_vrr_a(opcode, rn, rm, 3, 0, 0));
2644
}
2645
}
2646
&Inst::FpuCmp128 { rn, rm } => {
2647
let opcode = 0xe7cb; // WFC
2648
put(sink, &enc_vrr_a(opcode, rn, rm, 4, 0, 0));
2649
}
2650
2651
&Inst::VecRRR { op, rd, rn, rm } => {
2652
let (opcode, m4) = match op {
2653
VecBinaryOp::Add8x16 => (0xe7f3, 0), // VAB
2654
VecBinaryOp::Add16x8 => (0xe7f3, 1), // VAH
2655
VecBinaryOp::Add32x4 => (0xe7f3, 2), // VAF
2656
VecBinaryOp::Add64x2 => (0xe7f3, 3), // VAG
2657
VecBinaryOp::Add128 => (0xe7f3, 4), // VAQ
2658
VecBinaryOp::Sub8x16 => (0xe7f7, 0), // VSB
2659
VecBinaryOp::Sub16x8 => (0xe7f7, 1), // VSH
2660
VecBinaryOp::Sub32x4 => (0xe7f7, 2), // VSF
2661
VecBinaryOp::Sub64x2 => (0xe7f7, 3), // VSG
2662
VecBinaryOp::Sub128 => (0xe7f7, 4), // VSQ
2663
VecBinaryOp::Mul8x16 => (0xe7a2, 0), // VMLB
2664
VecBinaryOp::Mul16x8 => (0xe7a2, 1), // VMLHW
2665
VecBinaryOp::Mul32x4 => (0xe7a2, 2), // VMLF
2666
VecBinaryOp::UMulHi8x16 => (0xe7a1, 0), // VMLHB
2667
VecBinaryOp::UMulHi16x8 => (0xe7a1, 1), // VMLHH
2668
VecBinaryOp::UMulHi32x4 => (0xe7a1, 2), // VMLHF
2669
VecBinaryOp::SMulHi8x16 => (0xe7a3, 0), // VMHB
2670
VecBinaryOp::SMulHi16x8 => (0xe7a3, 1), // VMHH
2671
VecBinaryOp::SMulHi32x4 => (0xe7a3, 2), // VMHF
2672
VecBinaryOp::UMulEven8x16 => (0xe7a4, 0), // VMLEB
2673
VecBinaryOp::UMulEven16x8 => (0xe7a4, 1), // VMLEH
2674
VecBinaryOp::UMulEven32x4 => (0xe7a4, 2), // VMLEF
2675
VecBinaryOp::SMulEven8x16 => (0xe7a6, 0), // VMEB
2676
VecBinaryOp::SMulEven16x8 => (0xe7a6, 1), // VMEH
2677
VecBinaryOp::SMulEven32x4 => (0xe7a6, 2), // VMEF
2678
VecBinaryOp::UMulOdd8x16 => (0xe7a5, 0), // VMLOB
2679
VecBinaryOp::UMulOdd16x8 => (0xe7a5, 1), // VMLOH
2680
VecBinaryOp::UMulOdd32x4 => (0xe7a5, 2), // VMLOF
2681
VecBinaryOp::SMulOdd8x16 => (0xe7a7, 0), // VMOB
2682
VecBinaryOp::SMulOdd16x8 => (0xe7a7, 1), // VMOH
2683
VecBinaryOp::SMulOdd32x4 => (0xe7a7, 2), // VMOF
2684
VecBinaryOp::UMax8x16 => (0xe7fd, 0), // VMXLB
2685
VecBinaryOp::UMax16x8 => (0xe7fd, 1), // VMXLH
2686
VecBinaryOp::UMax32x4 => (0xe7fd, 2), // VMXLF
2687
VecBinaryOp::UMax64x2 => (0xe7fd, 3), // VMXLG
2688
VecBinaryOp::SMax8x16 => (0xe7ff, 0), // VMXB
2689
VecBinaryOp::SMax16x8 => (0xe7ff, 1), // VMXH
2690
VecBinaryOp::SMax32x4 => (0xe7ff, 2), // VMXF
2691
VecBinaryOp::SMax64x2 => (0xe7ff, 3), // VMXG
2692
VecBinaryOp::UMin8x16 => (0xe7fc, 0), // VMNLB
2693
VecBinaryOp::UMin16x8 => (0xe7fc, 1), // VMNLH
2694
VecBinaryOp::UMin32x4 => (0xe7fc, 2), // VMNLF
2695
VecBinaryOp::UMin64x2 => (0xe7fc, 3), // VMNLG
2696
VecBinaryOp::SMin8x16 => (0xe7fe, 0), // VMNB
2697
VecBinaryOp::SMin16x8 => (0xe7fe, 1), // VMNH
2698
VecBinaryOp::SMin32x4 => (0xe7fe, 2), // VMNF
2699
VecBinaryOp::SMin64x2 => (0xe7fe, 3), // VMNG
2700
VecBinaryOp::UAvg8x16 => (0xe7f0, 0), // VAVGLB
2701
VecBinaryOp::UAvg16x8 => (0xe7f0, 1), // VAVGLH
2702
VecBinaryOp::UAvg32x4 => (0xe7f0, 2), // VAVGLF
2703
VecBinaryOp::UAvg64x2 => (0xe7f0, 3), // VAVGLG
2704
VecBinaryOp::SAvg8x16 => (0xe7f2, 0), // VAVGB
2705
VecBinaryOp::SAvg16x8 => (0xe7f2, 1), // VAVGH
2706
VecBinaryOp::SAvg32x4 => (0xe7f2, 2), // VAVGF
2707
VecBinaryOp::SAvg64x2 => (0xe7f2, 3), // VAVGG
2708
VecBinaryOp::And128 => (0xe768, 0), // VN
2709
VecBinaryOp::Orr128 => (0xe76a, 0), // VO
2710
VecBinaryOp::Xor128 => (0xe76d, 0), // VX
2711
VecBinaryOp::NotAnd128 => (0xe76e, 0), // VNN
2712
VecBinaryOp::NotOrr128 => (0xe76b, 0), // VNO
2713
VecBinaryOp::NotXor128 => (0xe76c, 0), // VNX
2714
VecBinaryOp::AndNot128 => (0xe769, 0), // VNC
2715
VecBinaryOp::OrrNot128 => (0xe76f, 0), // VOC
2716
VecBinaryOp::BitPermute128 => (0xe785, 0), // VBPERM
2717
VecBinaryOp::LShLByByte128 => (0xe775, 0), // VSLB
2718
VecBinaryOp::LShRByByte128 => (0xe77d, 0), // VSRLB
2719
VecBinaryOp::AShRByByte128 => (0xe77f, 0), // VSRAB
2720
VecBinaryOp::LShLByBit128 => (0xe774, 0), // VSL
2721
VecBinaryOp::LShRByBit128 => (0xe77c, 0), // VSRL
2722
VecBinaryOp::AShRByBit128 => (0xe77e, 0), // VSRA
2723
VecBinaryOp::Pack16x8 => (0xe794, 1), // VPKH
2724
VecBinaryOp::Pack32x4 => (0xe794, 2), // VPKF
2725
VecBinaryOp::Pack64x2 => (0xe794, 3), // VPKG
2726
VecBinaryOp::PackUSat16x8 => (0xe795, 1), // VPKLSH
2727
VecBinaryOp::PackUSat32x4 => (0xe795, 2), // VPKLSF
2728
VecBinaryOp::PackUSat64x2 => (0xe795, 3), // VPKLSG
2729
VecBinaryOp::PackSSat16x8 => (0xe797, 1), // VPKSH
2730
VecBinaryOp::PackSSat32x4 => (0xe797, 2), // VPKSF
2731
VecBinaryOp::PackSSat64x2 => (0xe797, 3), // VPKSG
2732
VecBinaryOp::MergeLow8x16 => (0xe760, 0), // VMRLB
2733
VecBinaryOp::MergeLow16x8 => (0xe760, 1), // VMRLH
2734
VecBinaryOp::MergeLow32x4 => (0xe760, 2), // VMRLF
2735
VecBinaryOp::MergeLow64x2 => (0xe760, 3), // VMRLG
2736
VecBinaryOp::MergeHigh8x16 => (0xe761, 0), // VMRHB
2737
VecBinaryOp::MergeHigh16x8 => (0xe761, 1), // VMRHH
2738
VecBinaryOp::MergeHigh32x4 => (0xe761, 2), // VMRHF
2739
VecBinaryOp::MergeHigh64x2 => (0xe761, 3), // VMRHG
2740
};
2741
2742
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));
2743
}
2744
&Inst::VecRR { op, rd, rn } => {
2745
let (opcode, m3) = match op {
2746
VecUnaryOp::Abs8x16 => (0xe7df, 0), // VLPB
2747
VecUnaryOp::Abs16x8 => (0xe7df, 1), // VLPH
2748
VecUnaryOp::Abs32x4 => (0xe7df, 2), // VLPF
2749
VecUnaryOp::Abs64x2 => (0xe7df, 3), // VLPG
2750
VecUnaryOp::Neg8x16 => (0xe7de, 0), // VLCB
2751
VecUnaryOp::Neg16x8 => (0xe7de, 1), // VLCH
2752
VecUnaryOp::Neg32x4 => (0xe7de, 2), // VLCF
2753
VecUnaryOp::Neg64x2 => (0xe7de, 3), // VLCG
2754
VecUnaryOp::Popcnt8x16 => (0xe750, 0), // VPOPCTB
2755
VecUnaryOp::Popcnt16x8 => (0xe750, 1), // VPOPCTH
2756
VecUnaryOp::Popcnt32x4 => (0xe750, 2), // VPOPCTF
2757
VecUnaryOp::Popcnt64x2 => (0xe750, 3), // VPOPCTG
2758
VecUnaryOp::Clz8x16 => (0xe753, 0), // VCLZB
2759
VecUnaryOp::Clz16x8 => (0xe753, 1), // VCLZH
2760
VecUnaryOp::Clz32x4 => (0xe753, 2), // VCLZF
2761
VecUnaryOp::Clz64x2 => (0xe753, 3), // VCLZG
2762
VecUnaryOp::Ctz8x16 => (0xe752, 0), // VCTZB
2763
VecUnaryOp::Ctz16x8 => (0xe752, 1), // VCTZH
2764
VecUnaryOp::Ctz32x4 => (0xe752, 2), // VCTZF
2765
VecUnaryOp::Ctz64x2 => (0xe752, 3), // VCTZG
2766
VecUnaryOp::UnpackULow8x16 => (0xe7d4, 0), // VUPLLB
2767
VecUnaryOp::UnpackULow16x8 => (0xe7d4, 1), // VUPLLH
2768
VecUnaryOp::UnpackULow32x4 => (0xe7d4, 2), // VUPLLF
2769
VecUnaryOp::UnpackUHigh8x16 => (0xe7d5, 0), // VUPLHB
2770
VecUnaryOp::UnpackUHigh16x8 => (0xe7d5, 1), // VUPLHH
2771
VecUnaryOp::UnpackUHigh32x4 => (0xe7d5, 2), // VUPLHF
2772
VecUnaryOp::UnpackSLow8x16 => (0xe7d6, 0), // VUPLB
2773
VecUnaryOp::UnpackSLow16x8 => (0xe7d6, 1), // VUPLH
2774
VecUnaryOp::UnpackSLow32x4 => (0xe7d6, 2), // VUPLF
2775
VecUnaryOp::UnpackSHigh8x16 => (0xe7d7, 0), // VUPHB
2776
VecUnaryOp::UnpackSHigh16x8 => (0xe7d7, 1), // VUPHH
2777
VecUnaryOp::UnpackSHigh32x4 => (0xe7d7, 2), // VUPHF
2778
};
2779
2780
put(sink, &enc_vrr_a(opcode, rd.to_reg(), rn, m3, 0, 0));
2781
}
2782
&Inst::VecShiftRR {
2783
shift_op,
2784
rd,
2785
rn,
2786
shift_imm,
2787
shift_reg,
2788
} => {
2789
let (opcode, m4) = match shift_op {
2790
VecShiftOp::RotL8x16 => (0xe733, 0), // VERLLB
2791
VecShiftOp::RotL16x8 => (0xe733, 1), // VERLLH
2792
VecShiftOp::RotL32x4 => (0xe733, 2), // VERLLF
2793
VecShiftOp::RotL64x2 => (0xe733, 3), // VERLLG
2794
VecShiftOp::LShL8x16 => (0xe730, 0), // VESLB
2795
VecShiftOp::LShL16x8 => (0xe730, 1), // VESLH
2796
VecShiftOp::LShL32x4 => (0xe730, 2), // VESLF
2797
VecShiftOp::LShL64x2 => (0xe730, 3), // VESLG
2798
VecShiftOp::LShR8x16 => (0xe738, 0), // VESRLB
2799
VecShiftOp::LShR16x8 => (0xe738, 1), // VESRLH
2800
VecShiftOp::LShR32x4 => (0xe738, 2), // VESRLF
2801
VecShiftOp::LShR64x2 => (0xe738, 3), // VESRLG
2802
VecShiftOp::AShR8x16 => (0xe73a, 0), // VESRAB
2803
VecShiftOp::AShR16x8 => (0xe73a, 1), // VESRAH
2804
VecShiftOp::AShR32x4 => (0xe73a, 2), // VESRAF
2805
VecShiftOp::AShR64x2 => (0xe73a, 3), // VESRAG
2806
};
2807
put(
2808
sink,
2809
&enc_vrs_a(opcode, rd.to_reg(), shift_reg, shift_imm.into(), rn, m4),
2810
);
2811
}
2812
&Inst::VecSelect { rd, rn, rm, ra } => {
2813
let opcode = 0xe78d; // VSEL
2814
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2815
}
2816
&Inst::VecPermute { rd, rn, rm, ra } => {
2817
let opcode = 0xe78c; // VPERM
2818
put(sink, &enc_vrr_e(opcode, rd.to_reg(), rn, rm, ra, 0, 0));
2819
}
2820
&Inst::VecPermuteDWImm {
2821
rd,
2822
rn,
2823
rm,
2824
idx1,
2825
idx2,
2826
} => {
2827
let m4 = (idx1 & 1) * 4 + (idx2 & 1);
2828
2829
let opcode = 0xe784; // VPDI
2830
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, 0));
2831
}
2832
&Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {
2833
let (opcode, m4) = match op {
2834
VecIntCmpOp::CmpEq8x16 => (0xe7f8, 0), // VCEQB
2835
VecIntCmpOp::CmpEq16x8 => (0xe7f8, 1), // VCEQH
2836
VecIntCmpOp::CmpEq32x4 => (0xe7f8, 2), // VCEQF
2837
VecIntCmpOp::CmpEq64x2 => (0xe7f8, 3), // VCEQG
2838
VecIntCmpOp::SCmpHi8x16 => (0xe7fb, 0), // VCHB
2839
VecIntCmpOp::SCmpHi16x8 => (0xe7fb, 1), // VCHH
2840
VecIntCmpOp::SCmpHi32x4 => (0xe7fb, 2), // VCHG
2841
VecIntCmpOp::SCmpHi64x2 => (0xe7fb, 3), // VCHG
2842
VecIntCmpOp::UCmpHi8x16 => (0xe7f9, 0), // VCHLB
2843
VecIntCmpOp::UCmpHi16x8 => (0xe7f9, 1), // VCHLH
2844
VecIntCmpOp::UCmpHi32x4 => (0xe7f9, 2), // VCHLG
2845
VecIntCmpOp::UCmpHi64x2 => (0xe7f9, 3), // VCHLG
2846
};
2847
let m5 = match self {
2848
&Inst::VecIntCmp { .. } => 0,
2849
&Inst::VecIntCmpS { .. } => 1,
2850
_ => unreachable!(),
2851
};
2852
2853
put(sink, &enc_vrr_b(opcode, rd.to_reg(), rn, rm, m4, m5));
2854
}
2855
&Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {
2856
let (opcode, m4) = match op {
2857
VecFloatCmpOp::CmpEq32x4 => (0xe7e8, 2), // VFCESB
2858
VecFloatCmpOp::CmpEq64x2 => (0xe7e8, 3), // VFCEDB
2859
VecFloatCmpOp::CmpHi32x4 => (0xe7eb, 2), // VFCHSB
2860
VecFloatCmpOp::CmpHi64x2 => (0xe7eb, 3), // VFCHDB
2861
VecFloatCmpOp::CmpHiEq32x4 => (0xe7ea, 2), // VFCHESB
2862
VecFloatCmpOp::CmpHiEq64x2 => (0xe7ea, 3), // VFCHEDB
2863
};
2864
let m6 = match self {
2865
&Inst::VecFloatCmp { .. } => 0,
2866
&Inst::VecFloatCmpS { .. } => 1,
2867
_ => unreachable!(),
2868
};
2869
2870
put(sink, &enc_vrr_c(opcode, rd.to_reg(), rn, rm, m4, 0, m6));
2871
}
2872
&Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {
2873
// Synthetic instruction to compare 128-bit values.
2874
// Sets CC 1 if rn > rm, sets a different CC otherwise.
2875
2876
// Use VECTOR ELEMENT COMPARE to compare the high parts.
2877
// Swap the inputs to get:
2878
// CC 1 if high(rn) > high(rm)
2879
// CC 2 if high(rn) < high(rm)
2880
// CC 0 if high(rn) == high(rm)
2881
let (opcode, m3) = match self {
2882
&Inst::VecInt128SCmpHi { .. } => (0xe7db, 3), // VECG
2883
&Inst::VecInt128UCmpHi { .. } => (0xe7d9, 3), // VECLG
2884
_ => unreachable!(),
2885
};
2886
put(sink, &enc_vrr_a(opcode, rm, rn, m3, 0, 0));
2887
2888
// If CC != 0, we'd done, so jump over the next instruction.
2889
put(sink, &enc_ri_c(OPCODE_BCR, 7, 4 + 6));
2890
2891
// Otherwise, use VECTOR COMPARE HIGH LOGICAL.
2892
// Since we already know the high parts are equal, the CC
2893
// result will only depend on the low parts:
2894
// CC 1 if low(rn) > low(rm)
2895
// CC 3 if low(rn) <= low(rm)
2896
let inst = Inst::VecIntCmpS {
2897
op: VecIntCmpOp::UCmpHi64x2,
2898
// N.B.: This is the first write to tmp, and it happens
2899
// after all uses of rn and rm. If this were to ever
2900
// change, tmp would have to become an early-def.
2901
rd: tmp,
2902
rn,
2903
rm,
2904
};
2905
inst.emit(sink, emit_info, state);
2906
}
2907
2908
&Inst::VecLoad { rd, ref mem }
2909
| &Inst::VecLoadRev { rd, ref mem }
2910
| &Inst::VecLoadByte16Rev { rd, ref mem }
2911
| &Inst::VecLoadByte32Rev { rd, ref mem }
2912
| &Inst::VecLoadByte64Rev { rd, ref mem }
2913
| &Inst::VecLoadElt16Rev { rd, ref mem }
2914
| &Inst::VecLoadElt32Rev { rd, ref mem }
2915
| &Inst::VecLoadElt64Rev { rd, ref mem } => {
2916
let mem = mem.clone();
2917
2918
let (opcode, m3) = match self {
2919
&Inst::VecLoad { .. } => (0xe706, 0), // VL
2920
&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ
2921
&Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH
2922
&Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF
2923
&Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG
2924
&Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH
2925
&Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF
2926
&Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG
2927
_ => unreachable!(),
2928
};
2929
mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
2930
}
2931
&Inst::VecStore { rd, ref mem }
2932
| &Inst::VecStoreRev { rd, ref mem }
2933
| &Inst::VecStoreByte16Rev { rd, ref mem }
2934
| &Inst::VecStoreByte32Rev { rd, ref mem }
2935
| &Inst::VecStoreByte64Rev { rd, ref mem }
2936
| &Inst::VecStoreElt16Rev { rd, ref mem }
2937
| &Inst::VecStoreElt32Rev { rd, ref mem }
2938
| &Inst::VecStoreElt64Rev { rd, ref mem } => {
2939
let mem = mem.clone();
2940
2941
let (opcode, m3) = match self {
2942
&Inst::VecStore { .. } => (0xe70e, 0), // VST
2943
&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ
2944
&Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH
2945
&Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF
2946
&Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG
2947
&Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH
2948
&Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF
2949
&Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG
2950
_ => unreachable!(),
2951
};
2952
mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);
2953
}
2954
&Inst::VecLoadReplicate { size, rd, ref mem }
2955
| &Inst::VecLoadReplicateRev { size, rd, ref mem } => {
2956
let mem = mem.clone();
2957
2958
let (opcode, m3) = match (self, size) {
2959
(&Inst::VecLoadReplicate { .. }, 8) => (0xe705, 0), // VLREPB
2960
(&Inst::VecLoadReplicate { .. }, 16) => (0xe705, 1), // VLREPH
2961
(&Inst::VecLoadReplicate { .. }, 32) => (0xe705, 2), // VLREPF
2962
(&Inst::VecLoadReplicate { .. }, 64) => (0xe705, 3), // VLREPG
2963
(&Inst::VecLoadReplicateRev { .. }, 16) => (0xe605, 1), // VLREPBRH
2964
(&Inst::VecLoadReplicateRev { .. }, 32) => (0xe605, 2), // VLREPBRF
2965
(&Inst::VecLoadReplicateRev { .. }, 64) => (0xe605, 3), // VLREPBRG
2966
_ => unreachable!(),
2967
};
2968
mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
2969
}
2970
2971
&Inst::VecMov { rd, rn } => {
2972
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rn, 0, 0, 0));
2973
}
2974
&Inst::VecCMov { rd, cond, ri, rm } => {
2975
debug_assert_eq!(rd.to_reg(), ri);
2976
2977
put(sink, &enc_ri_c(OPCODE_BCR, cond.invert().bits(), 4 + 6));
2978
put(sink, &enc_vrr_a(OPCODE_VLR, rd.to_reg(), rm, 0, 0, 0));
2979
}
2980
&Inst::MovToVec128 { rd, rn, rm } => {
2981
let opcode = 0xe762; // VLVGP
2982
put(sink, &enc_vrr_f(opcode, rd.to_reg(), rn, rm));
2983
}
2984
&Inst::VecImmByteMask { rd, mask } => {
2985
let opcode = 0xe744; // VGBM
2986
put(sink, &enc_vri_a(opcode, rd.to_reg(), mask, 0));
2987
}
2988
&Inst::VecImmBitMask {
2989
size,
2990
rd,
2991
start_bit,
2992
end_bit,
2993
} => {
2994
let (opcode, m4) = match size {
2995
8 => (0xe746, 0), // VGMB
2996
16 => (0xe746, 1), // VGMH
2997
32 => (0xe746, 2), // VGMF
2998
64 => (0xe746, 3), // VGMG
2999
_ => unreachable!(),
3000
};
3001
put(
3002
sink,
3003
&enc_vri_b(opcode, rd.to_reg(), start_bit, end_bit, m4),
3004
);
3005
}
3006
&Inst::VecImmReplicate { size, rd, imm } => {
3007
let (opcode, m3) = match size {
3008
8 => (0xe745, 0), // VREPIB
3009
16 => (0xe745, 1), // VREPIH
3010
32 => (0xe745, 2), // VREPIF
3011
64 => (0xe745, 3), // VREPIG
3012
_ => unreachable!(),
3013
};
3014
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, m3));
3015
}
3016
&Inst::VecLoadLane {
3017
size,
3018
rd,
3019
ri,
3020
ref mem,
3021
lane_imm,
3022
}
3023
| &Inst::VecLoadLaneRev {
3024
size,
3025
rd,
3026
ri,
3027
ref mem,
3028
lane_imm,
3029
} => {
3030
debug_assert_eq!(rd.to_reg(), ri);
3031
let mem = mem.clone();
3032
3033
let opcode_vrx = match (self, size) {
3034
(&Inst::VecLoadLane { .. }, 8) => 0xe700, // VLEB
3035
(&Inst::VecLoadLane { .. }, 16) => 0xe701, // VLEH
3036
(&Inst::VecLoadLane { .. }, 32) => 0xe703, // VLEF
3037
(&Inst::VecLoadLane { .. }, 64) => 0xe702, // VLEG
3038
(&Inst::VecLoadLaneRev { .. }, 16) => 0xe601, // VLEBRH
3039
(&Inst::VecLoadLaneRev { .. }, 32) => 0xe603, // VLEBRF
3040
(&Inst::VecLoadLaneRev { .. }, 64) => 0xe602, // VLEBRG
3041
_ => unreachable!(),
3042
};
3043
3044
let rd = rd.to_reg();
3045
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3046
}
3047
&Inst::VecLoadLaneUndef {
3048
size,
3049
rd,
3050
ref mem,
3051
lane_imm,
3052
}
3053
| &Inst::VecLoadLaneRevUndef {
3054
size,
3055
rd,
3056
ref mem,
3057
lane_imm,
3058
} => {
3059
let mem = mem.clone();
3060
3061
let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3062
(&Inst::VecLoadLaneUndef { .. }, 8) => (0xe700, None, None), // VLEB
3063
(&Inst::VecLoadLaneUndef { .. }, 16) => (0xe701, None, None), // VLEH
3064
(&Inst::VecLoadLaneUndef { .. }, 32) => (0xe703, Some(0x78), Some(0xed64)), // VLEF, LE(Y)
3065
(&Inst::VecLoadLaneUndef { .. }, 64) => (0xe702, Some(0x68), Some(0xed65)), // VLEG, LD(Y)
3066
(&Inst::VecLoadLaneRevUndef { .. }, 16) => (0xe601, None, None), // VLEBRH
3067
(&Inst::VecLoadLaneRevUndef { .. }, 32) => (0xe603, None, None), // VLEBRF
3068
(&Inst::VecLoadLaneRevUndef { .. }, 64) => (0xe602, None, None), // VLEBRG
3069
_ => unreachable!(),
3070
};
3071
3072
let rd = rd.to_reg();
3073
if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3074
mem_emit(
3075
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3076
);
3077
} else {
3078
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3079
}
3080
}
3081
&Inst::VecStoreLane {
3082
size,
3083
rd,
3084
ref mem,
3085
lane_imm,
3086
}
3087
| &Inst::VecStoreLaneRev {
3088
size,
3089
rd,
3090
ref mem,
3091
lane_imm,
3092
} => {
3093
let mem = mem.clone();
3094
3095
let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3096
(&Inst::VecStoreLane { .. }, 8) => (0xe708, None, None), // VSTEB
3097
(&Inst::VecStoreLane { .. }, 16) => (0xe709, None, None), // VSTEH
3098
(&Inst::VecStoreLane { .. }, 32) => (0xe70b, Some(0x70), Some(0xed66)), // VSTEF, STE(Y)
3099
(&Inst::VecStoreLane { .. }, 64) => (0xe70a, Some(0x60), Some(0xed67)), // VSTEG, STD(Y)
3100
(&Inst::VecStoreLaneRev { .. }, 16) => (0xe609, None, None), // VSTEBRH
3101
(&Inst::VecStoreLaneRev { .. }, 32) => (0xe60b, None, None), // VSTEBRF
3102
(&Inst::VecStoreLaneRev { .. }, 64) => (0xe60a, None, None), // VSTEBRG
3103
_ => unreachable!(),
3104
};
3105
3106
if lane_imm == 0 && is_fpr(rd) && opcode_rx.is_some() {
3107
mem_emit(
3108
rd, &mem, opcode_rx, opcode_rxy, None, true, sink, emit_info, state,
3109
);
3110
} else {
3111
mem_vrx_emit(rd, &mem, opcode_vrx, lane_imm, true, sink, emit_info, state);
3112
}
3113
}
3114
&Inst::VecInsertLane {
3115
size,
3116
rd,
3117
ri,
3118
rn,
3119
lane_imm,
3120
lane_reg,
3121
} => {
3122
debug_assert_eq!(rd.to_reg(), ri);
3123
3124
let (opcode_vrs, m4) = match size {
3125
8 => (0xe722, 0), // VLVGB
3126
16 => (0xe722, 1), // VLVGH
3127
32 => (0xe722, 2), // VLVGF
3128
64 => (0xe722, 3), // VLVGG
3129
_ => unreachable!(),
3130
};
3131
put(
3132
sink,
3133
&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3134
);
3135
}
3136
&Inst::VecInsertLaneUndef {
3137
size,
3138
rd,
3139
rn,
3140
lane_imm,
3141
lane_reg,
3142
} => {
3143
let (opcode_vrs, m4, opcode_rre) = match size {
3144
8 => (0xe722, 0, None), // VLVGB
3145
16 => (0xe722, 1, None), // VLVGH
3146
32 => (0xe722, 2, None), // VLVGF
3147
64 => (0xe722, 3, Some(0xb3c1)), // VLVGG, LDGR
3148
_ => unreachable!(),
3149
};
3150
if opcode_rre.is_some()
3151
&& lane_imm == 0
3152
&& lane_reg == zero_reg()
3153
&& is_fpr(rd.to_reg())
3154
{
3155
put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3156
} else {
3157
put(
3158
sink,
3159
&enc_vrs_b(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3160
);
3161
}
3162
}
3163
&Inst::VecExtractLane {
3164
size,
3165
rd,
3166
rn,
3167
lane_imm,
3168
lane_reg,
3169
} => {
3170
let (opcode_vrs, m4, opcode_rre) = match size {
3171
8 => (0xe721, 0, None), // VLGVB
3172
16 => (0xe721, 1, None), // VLGVH
3173
32 => (0xe721, 2, None), // VLGVF
3174
64 => (0xe721, 3, Some(0xb3cd)), // VLGVG, LGDR
3175
_ => unreachable!(),
3176
};
3177
if opcode_rre.is_some() && lane_imm == 0 && lane_reg == zero_reg() && is_fpr(rn) {
3178
put(sink, &enc_rre(opcode_rre.unwrap(), rd.to_reg(), rn));
3179
} else {
3180
put(
3181
sink,
3182
&enc_vrs_c(opcode_vrs, rd.to_reg(), lane_reg, lane_imm.into(), rn, m4),
3183
);
3184
}
3185
}
3186
&Inst::VecInsertLaneImm {
3187
size,
3188
rd,
3189
ri,
3190
imm,
3191
lane_imm,
3192
} => {
3193
debug_assert_eq!(rd.to_reg(), ri);
3194
3195
let opcode = match size {
3196
8 => 0xe740, // VLEIB
3197
16 => 0xe741, // VLEIH
3198
32 => 0xe743, // VLEIF
3199
64 => 0xe742, // VLEIG
3200
_ => unreachable!(),
3201
};
3202
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));
3203
}
3204
&Inst::VecInsertLaneImmUndef {
3205
size,
3206
rd,
3207
imm,
3208
lane_imm,
3209
} => {
3210
let opcode = match size {
3211
8 => 0xe740, // VLEIB
3212
16 => 0xe741, // VLEIH
3213
32 => 0xe743, // VLEIF
3214
64 => 0xe742, // VLEIG
3215
_ => unreachable!(),
3216
};
3217
put(sink, &enc_vri_a(opcode, rd.to_reg(), imm as u16, lane_imm));
3218
}
3219
&Inst::VecReplicateLane {
3220
size,
3221
rd,
3222
rn,
3223
lane_imm,
3224
} => {
3225
let (opcode, m4) = match size {
3226
8 => (0xe74d, 0), // VREPB
3227
16 => (0xe74d, 1), // VREPH
3228
32 => (0xe74d, 2), // VREPF
3229
64 => (0xe74d, 3), // VREPG
3230
_ => unreachable!(),
3231
};
3232
put(
3233
sink,
3234
&enc_vri_c(opcode, rd.to_reg(), lane_imm.into(), rn, m4),
3235
);
3236
}
3237
3238
&Inst::VecEltRev { lane_count, rd, rn } => {
3239
assert!(lane_count >= 2 && lane_count <= 16);
3240
let inst = Inst::VecPermuteDWImm {
3241
rd,
3242
rn,
3243
rm: rn,
3244
idx1: 1,
3245
idx2: 0,
3246
};
3247
inst.emit(sink, emit_info, state);
3248
if lane_count >= 4 {
3249
let inst = Inst::VecShiftRR {
3250
shift_op: VecShiftOp::RotL64x2,
3251
rd,
3252
rn: rd.to_reg(),
3253
shift_imm: 32,
3254
shift_reg: zero_reg(),
3255
};
3256
inst.emit(sink, emit_info, state);
3257
}
3258
if lane_count >= 8 {
3259
let inst = Inst::VecShiftRR {
3260
shift_op: VecShiftOp::RotL32x4,
3261
rd,
3262
rn: rd.to_reg(),
3263
shift_imm: 16,
3264
shift_reg: zero_reg(),
3265
};
3266
inst.emit(sink, emit_info, state);
3267
}
3268
if lane_count >= 16 {
3269
let inst = Inst::VecShiftRR {
3270
shift_op: VecShiftOp::RotL16x8,
3271
rd,
3272
rn: rd.to_reg(),
3273
shift_imm: 8,
3274
shift_reg: zero_reg(),
3275
};
3276
inst.emit(sink, emit_info, state);
3277
}
3278
}
3279
3280
&Inst::AllocateArgs { size } => {
3281
let inst = if let Ok(size) = i16::try_from(size) {
3282
Inst::AluRSImm16 {
3283
alu_op: ALUOp::Add64,
3284
rd: writable_stack_reg(),
3285
ri: stack_reg(),
3286
imm: -size,
3287
}
3288
} else {
3289
Inst::AluRUImm32 {
3290
alu_op: ALUOp::SubLogical64,
3291
rd: writable_stack_reg(),
3292
ri: stack_reg(),
3293
imm: size,
3294
}
3295
};
3296
inst.emit(sink, emit_info, state);
3297
assert_eq!(state.nominal_sp_offset, 0);
3298
state.nominal_sp_offset += size;
3299
}
3300
&Inst::Call { link, ref info } => {
3301
let enc: &[u8] = match &info.dest {
3302
CallInstDest::Direct { name } => {
3303
let offset = sink.cur_offset() + 2;
3304
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);
3305
let opcode = 0xc05; // BRASL
3306
&enc_ril_b(opcode, link.to_reg(), 0)
3307
}
3308
CallInstDest::Indirect { reg } => {
3309
let opcode = 0x0d; // BASR
3310
&enc_rr(opcode, link.to_reg(), *reg)
3311
}
3312
};
3313
if let Some(s) = state.take_stack_map() {
3314
let offset = sink.cur_offset() + enc.len() as u32;
3315
sink.push_user_stack_map(state, offset, s);
3316
}
3317
put(sink, enc);
3318
3319
if let Some(try_call) = info.try_call_info.as_ref() {
3320
sink.add_try_call_site(
3321
Some(state.frame_layout.sp_to_fp()),
3322
try_call.exception_handlers(&state.frame_layout),
3323
);
3324
} else {
3325
sink.add_call_site();
3326
}
3327
3328
state.nominal_sp_offset -= info.callee_pop_size;
3329
assert_eq!(state.nominal_sp_offset, 0);
3330
3331
state.outgoing_sp_offset = info.callee_pop_size;
3332
for inst in S390xMachineDeps::gen_retval_loads(info) {
3333
inst.emit(sink, emit_info, state);
3334
}
3335
state.outgoing_sp_offset = 0;
3336
3337
// If this is a try-call, jump to the continuation
3338
// (normal-return) block.
3339
if let Some(try_call) = info.try_call_info.as_ref() {
3340
let jmp = Inst::Jump {
3341
dest: try_call.continuation,
3342
};
3343
jmp.emit(sink, emit_info, state);
3344
}
3345
}
3346
&Inst::ReturnCall { ref info } => {
3347
let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(
3348
state.frame_layout(),
3349
info.callee_pop_size,
3350
&info.dest,
3351
);
3352
for inst in epilogue_insts {
3353
inst.emit(sink, emit_info, state);
3354
}
3355
3356
let enc: &[u8] = match &info.dest {
3357
CallInstDest::Direct { name } => {
3358
let offset = sink.cur_offset() + 2;
3359
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, name, 2);
3360
let opcode = 0xc04; // BCRL
3361
&enc_ril_c(opcode, 15, 0)
3362
}
3363
CallInstDest::Indirect { reg } => {
3364
let opcode = 0x07; // BCR
3365
&enc_rr(opcode, gpr(15), temp_dest.unwrap_or(*reg))
3366
}
3367
};
3368
put(sink, enc);
3369
sink.add_call_site();
3370
}
3371
&Inst::ElfTlsGetOffset { ref symbol, .. } => {
3372
let opcode = 0xc05; // BRASL
3373
3374
// Add relocation for target function. This has to be done
3375
// *before* the S390xTlsGdCall, to ensure linker relaxation
3376
// works correctly.
3377
let dest = ExternalName::LibCall(LibCall::ElfTlsGetOffset);
3378
let offset = sink.cur_offset() + 2;
3379
sink.add_reloc_at_offset(offset, Reloc::S390xPLTRel32Dbl, &dest, 2);
3380
match &**symbol {
3381
SymbolReloc::TlsGd { name } => sink.add_reloc(Reloc::S390xTlsGdCall, name, 0),
3382
_ => unreachable!(),
3383
}
3384
3385
put(sink, &enc_ril_b(opcode, gpr(14), 0));
3386
sink.add_call_site();
3387
}
3388
&Inst::Args { .. } => {}
3389
&Inst::Rets { .. } => {}
3390
&Inst::Ret { link } => {
3391
let opcode = 0x07; // BCR
3392
put(sink, &enc_rr(opcode, gpr(15), link));
3393
}
3394
&Inst::Jump { dest } => {
3395
let off = sink.cur_offset();
3396
// Indicate that the jump uses a label, if so, so that a fixup can occur later.
3397
sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);
3398
sink.add_uncond_branch(off, off + 6, dest);
3399
// Emit the jump itself.
3400
let opcode = 0xc04; // BCRL
3401
put(sink, &enc_ril_c(opcode, 15, 0));
3402
}
3403
&Inst::IndirectBr { rn, .. } => {
3404
let opcode = 0x07; // BCR
3405
put(sink, &enc_rr(opcode, gpr(15), rn));
3406
}
3407
&Inst::CondBr {
3408
taken,
3409
not_taken,
3410
cond,
3411
} => {
3412
let opcode = 0xc04; // BCRL
3413
3414
// Conditional part first.
3415
let cond_off = sink.cur_offset();
3416
sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);
3417
let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);
3418
sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);
3419
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
3420
3421
// Unconditional part next.
3422
let uncond_off = sink.cur_offset();
3423
sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);
3424
sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);
3425
put(sink, &enc_ril_c(opcode, 15, 0));
3426
}
3427
&Inst::Nop0 => {}
3428
&Inst::Nop2 => {
3429
put(sink, &enc_e(0x0707));
3430
}
3431
&Inst::Debugtrap => {
3432
put(sink, &enc_e(0x0001));
3433
}
3434
&Inst::Trap { trap_code } => {
3435
put_with_trap(sink, &enc_e(0x0000), trap_code);
3436
}
3437
&Inst::TrapIf { cond, trap_code } => {
3438
// We implement a TrapIf as a conditional branch into the middle
3439
// of the branch (BRCL) instruction itself - those middle two bytes
3440
// are zero, which matches the trap instruction itself.
3441
let opcode = 0xc04; // BCRL
3442
let enc = &enc_ril_c(opcode, cond.bits(), 2);
3443
debug_assert!(enc.len() == 6 && enc[2] == 0 && enc[3] == 0);
3444
// The trap must be placed on the last byte of the embedded trap
3445
// instruction, so we need to emit the encoding in two parts.
3446
put_with_trap(sink, &enc[0..4], trap_code);
3447
put(sink, &enc[4..6]);
3448
}
3449
&Inst::JTSequence {
3450
ridx,
3451
default,
3452
default_cond,
3453
ref targets,
3454
} => {
3455
let table_label = sink.get_label();
3456
3457
// This sequence is *one* instruction in the vcode, and is expanded only here at
3458
// emission time, because we cannot allow the regalloc to insert spills/reloads in
3459
// the middle; we depend on hardcoded PC-rel addressing below.
3460
3461
// Branch to the default target if the given default condition is true.
3462
let opcode = 0xc04; // BCRL
3463
sink.use_label_at_offset(sink.cur_offset(), default, LabelUse::BranchRIL);
3464
put(sink, &enc_ril_c(opcode, default_cond.bits(), 0));
3465
3466
// Set temp register to address of jump table.
3467
let rtmp = writable_spilltmp_reg();
3468
let inst = Inst::LoadAddr {
3469
rd: rtmp,
3470
mem: MemArg::Label {
3471
target: table_label,
3472
},
3473
};
3474
inst.emit(sink, emit_info, state);
3475
3476
// Set temp to target address by adding the value of the jump table entry.
3477
let inst = Inst::AluRX {
3478
alu_op: ALUOp::Add64Ext32,
3479
rd: rtmp,
3480
ri: rtmp.to_reg(),
3481
mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),
3482
};
3483
inst.emit(sink, emit_info, state);
3484
3485
// Branch to computed address. (`targets` here is only used for successor queries
3486
// and is not needed for emission.)
3487
let inst = Inst::IndirectBr {
3488
rn: rtmp.to_reg(),
3489
targets: vec![],
3490
};
3491
inst.emit(sink, emit_info, state);
3492
3493
// Emit jump table (table of 32-bit offsets).
3494
sink.bind_label(table_label, &mut state.ctrl_plane);
3495
let jt_off = sink.cur_offset();
3496
for &target in targets.iter() {
3497
let word_off = sink.cur_offset();
3498
let off_into_table = word_off - jt_off;
3499
sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3500
sink.put4(off_into_table.swap_bytes());
3501
}
3502
}
3503
3504
Inst::StackProbeLoop {
3505
probe_count,
3506
guard_size,
3507
} => {
3508
// Emit the loop start label
3509
let loop_start = sink.get_label();
3510
sink.bind_label(loop_start, state.ctrl_plane_mut());
3511
3512
// aghi %r15, -GUARD_SIZE
3513
let inst = Inst::AluRSImm16 {
3514
alu_op: ALUOp::Add64,
3515
rd: writable_stack_reg(),
3516
ri: stack_reg(),
3517
imm: -guard_size,
3518
};
3519
inst.emit(sink, emit_info, state);
3520
3521
// mvi 0(%r15), 0
3522
let inst = Inst::StoreImm8 {
3523
imm: 0,
3524
mem: MemArg::reg(stack_reg(), MemFlags::trusted()),
3525
};
3526
inst.emit(sink, emit_info, state);
3527
3528
// brct PROBE_COUNT, LOOP_START
3529
let opcode = 0xa76; // BRCT
3530
sink.use_label_at_offset(sink.cur_offset(), loop_start, LabelUse::BranchRI);
3531
put(sink, &enc_ri_b(opcode, probe_count.to_reg(), 0));
3532
}
3533
3534
&Inst::Unwind { ref inst } => {
3535
sink.add_unwind(inst.clone());
3536
}
3537
3538
&Inst::DummyUse { .. } => {}
3539
3540
&Inst::LabelAddress { dst, label } => {
3541
let inst = Inst::LoadAddr {
3542
rd: dst,
3543
mem: MemArg::Label { target: label },
3544
};
3545
inst.emit(sink, emit_info, state);
3546
}
3547
}
3548
3549
state.clear_post_insn();
3550
}
3551
}
3552
3553