Skip to content

Commit 0a1ef16

Browse files
committed
Disassociate InsnOut from Insn index
1 parent 8220b91 commit 0a1ef16

File tree

3 files changed

+253
-402
lines changed

3 files changed

+253
-402
lines changed

zjit/src/backend/arm64/mod.rs

Lines changed: 51 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ impl From<Opnd> for A64Opnd {
6767
Opnd::Mem(Mem { base: MemBase::Reg(reg_no), num_bits, disp }) => {
6868
A64Opnd::new_mem(num_bits, A64Opnd::Reg(A64Reg { num_bits, reg_no }), disp)
6969
},
70-
Opnd::Mem(Mem { base: MemBase::InsnOut(_), .. }) => {
71-
panic!("attempted to lower an Opnd::Mem with a MemBase::InsnOut base")
70+
Opnd::Mem(Mem { base: MemBase::VReg(_), .. }) => {
71+
panic!("attempted to lower an Opnd::Mem with a MemBase::VReg base")
7272
},
7373
Opnd::CArg(_) => panic!("attempted to lower an Opnd::CArg"),
74-
Opnd::InsnOut { .. } => panic!("attempted to lower an Opnd::InsnOut"),
74+
Opnd::VReg { .. } => panic!("attempted to lower an Opnd::VReg"),
7575
Opnd::Param { .. } => panic!("attempted to lower an Opnd::Param"),
7676
Opnd::Value(_) => panic!("attempted to lower an Opnd::Value"),
7777
Opnd::None => panic!(
@@ -226,7 +226,7 @@ impl Assembler
226226
let disp = asm.load(Opnd::Imm(disp.into()));
227227
let reg = match base {
228228
MemBase::Reg(reg_no) => Opnd::Reg(Reg { reg_no, num_bits }),
229-
MemBase::InsnOut(idx) => Opnd::InsnOut { idx, num_bits }
229+
MemBase::VReg(idx) => Opnd::VReg { idx, num_bits }
230230
};
231231

232232
asm.add(reg, disp)
@@ -258,7 +258,7 @@ impl Assembler
258258
/// to be split in case their displacement doesn't fit into 9 bits.
259259
fn split_load_operand(asm: &mut Assembler, opnd: Opnd) -> Opnd {
260260
match opnd {
261-
Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd,
261+
Opnd::Reg(_) | Opnd::VReg { .. } => opnd,
262262
Opnd::Mem(_) => {
263263
let split_opnd = split_memory_address(asm, opnd);
264264
let out_opnd = asm.load(split_opnd);
@@ -279,7 +279,7 @@ impl Assembler
279279
/// do follow that encoding, and if they don't then we load them first.
280280
fn split_bitmask_immediate(asm: &mut Assembler, opnd: Opnd, dest_num_bits: u8) -> Opnd {
281281
match opnd {
282-
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::InsnOut { .. } | Opnd::Param { .. } => opnd,
282+
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::VReg { .. } | Opnd::Param { .. } => opnd,
283283
Opnd::Mem(_) => split_load_operand(asm, opnd),
284284
Opnd::Imm(imm) => {
285285
if imm == 0 {
@@ -312,7 +312,7 @@ impl Assembler
312312
/// a certain size. If they don't then we need to load them first.
313313
fn split_shifted_immediate(asm: &mut Assembler, opnd: Opnd) -> Opnd {
314314
match opnd {
315-
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::InsnOut { .. } | Opnd::Param { .. } => opnd,
315+
Opnd::Reg(_) | Opnd::CArg(_) | Opnd::VReg { .. } | Opnd::Param { .. } => opnd,
316316
Opnd::Mem(_) => split_load_operand(asm, opnd),
317317
Opnd::Imm(imm) => if ShiftedImmediate::try_from(imm as u64).is_ok() {
318318
opnd
@@ -353,12 +353,12 @@ impl Assembler
353353
/// Returns the operands that should be used for a csel instruction.
354354
fn split_csel_operands(asm: &mut Assembler, opnd0: Opnd, opnd1: Opnd) -> (Opnd, Opnd) {
355355
let opnd0 = match opnd0 {
356-
Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd0,
356+
Opnd::Reg(_) | Opnd::VReg { .. } => opnd0,
357357
_ => split_load_operand(asm, opnd0)
358358
};
359359

360360
let opnd1 = match opnd1 {
361-
Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd1,
361+
Opnd::Reg(_) | Opnd::VReg { .. } => opnd1,
362362
_ => split_load_operand(asm, opnd1)
363363
};
364364

@@ -367,7 +367,7 @@ impl Assembler
367367

368368
fn split_less_than_32_cmp(asm: &mut Assembler, opnd0: Opnd) -> Opnd {
369369
match opnd0 {
370-
Opnd::Reg(_) | Opnd::InsnOut { .. } => {
370+
Opnd::Reg(_) | Opnd::VReg { .. } => {
371371
match opnd0.rm_num_bits() {
372372
8 => asm.and(opnd0.with_num_bits(64).unwrap(), Opnd::UImm(0xff)),
373373
16 => asm.and(opnd0.with_num_bits(64).unwrap(), Opnd::UImm(0xffff)),
@@ -379,12 +379,12 @@ impl Assembler
379379
}
380380
}
381381

382-
let live_ranges: Vec<usize> = take(&mut self.live_ranges);
383-
let mut asm_local = Assembler::new_with_label_names(take(&mut self.label_names));
382+
let live_ranges: Vec<LiveRange> = take(&mut self.live_ranges);
383+
let mut iterator = self.insns.into_iter().enumerate().peekable();
384+
let mut asm_local = Assembler::new_with_label_names(take(&mut self.label_names), live_ranges.len());
384385
let asm = &mut asm_local;
385-
let mut iterator = self.into_draining_iter();
386386

387-
while let Some((index, mut insn)) = iterator.next_mapped() {
387+
while let Some((index, mut insn)) = iterator.next() {
388388
// Here we're going to map the operands of the instruction to load
389389
// any Opnd::Value operands into registers if they are heap objects
390390
// such that only the Op::Load instruction needs to handle that
@@ -415,18 +415,19 @@ impl Assembler
415415
match &mut insn {
416416
Insn::Add { left, right, .. } => {
417417
match (*left, *right) {
418-
(Opnd::Reg(_) | Opnd::InsnOut { .. }, Opnd::Reg(_) | Opnd::InsnOut { .. }) => {
419-
asm.add(*left, *right);
418+
(Opnd::Reg(_) | Opnd::VReg { .. }, Opnd::Reg(_) | Opnd::VReg { .. }) => {
419+
asm.push_insn(insn);
420420
},
421-
(reg_opnd @ (Opnd::Reg(_) | Opnd::InsnOut { .. }), other_opnd) |
422-
(other_opnd, reg_opnd @ (Opnd::Reg(_) | Opnd::InsnOut { .. })) => {
423-
let opnd1 = split_shifted_immediate(asm, other_opnd);
424-
asm.add(reg_opnd, opnd1);
421+
(reg_opnd @ (Opnd::Reg(_) | Opnd::VReg { .. }), other_opnd) |
422+
(other_opnd, reg_opnd @ (Opnd::Reg(_) | Opnd::VReg { .. })) => {
423+
*left = reg_opnd;
424+
*right = split_shifted_immediate(asm, other_opnd);
425+
asm.push_insn(insn);
425426
},
426427
_ => {
427-
let opnd0 = split_load_operand(asm, *left);
428-
let opnd1 = split_shifted_immediate(asm, *right);
429-
asm.add(opnd0, opnd1);
428+
*left = split_load_operand(asm, *left);
429+
*right = split_shifted_immediate(asm, *right);
430+
asm.push_insn(insn);
430431
}
431432
}
432433
},
@@ -441,19 +442,11 @@ impl Assembler
441442
// registers and an output register, look to merge with an `Insn::Mov` that
442443
// follows which puts the output in another register. For example:
443444
// `Add a, b => out` followed by `Mov c, out` becomes `Add a, b => c`.
444-
if let (Opnd::Reg(_), Opnd::Reg(_), Some(Insn::Mov { dest, src })) = (left, right, iterator.peek()) {
445-
if live_ranges[index] == index + 1 {
446-
// Check after potentially lowering a stack operand to a register operand
447-
//let lowered_dest = if let Opnd::Stack { .. } = dest {
448-
// asm.lower_stack_opnd(dest)
449-
//} else {
450-
// *dest
451-
//};
452-
let lowered_dest = *dest;
453-
if out == src && matches!(lowered_dest, Opnd::Reg(_)) {
454-
*out = lowered_dest;
455-
iterator.map_insn_index(asm);
456-
iterator.next_unmapped(); // Pop merged Insn::Mov
445+
if let (Opnd::Reg(_), Opnd::Reg(_), Some(Insn::Mov { dest, src })) = (left, right, iterator.peek().map(|(_, insn)| insn)) {
446+
if live_ranges[out.vreg_idx()].end() == index + 1 {
447+
if out == src && matches!(*dest, Opnd::Reg(_)) {
448+
*out = *dest;
449+
iterator.next(); // Pop merged Insn::Mov
457450
}
458451
}
459452
}
@@ -489,7 +482,7 @@ impl Assembler
489482
iterator.next_unmapped(); // Pop merged jump instruction
490483
}
491484
*/
492-
Insn::CCall { opnds, fptr, .. } => {
485+
Insn::CCall { opnds, .. } => {
493486
assert!(opnds.len() <= C_ARG_OPNDS.len());
494487

495488
// Load each operand into the corresponding argument
@@ -511,14 +504,15 @@ impl Assembler
511504

512505
// Now we push the CCall without any arguments so that it
513506
// just performs the call.
514-
asm.ccall(*fptr, vec![]);
507+
*opnds = vec![];
508+
asm.push_insn(insn);
515509
},
516510
Insn::Cmp { left, right } => {
517511
let opnd0 = split_load_operand(asm, *left);
518512
let opnd0 = split_less_than_32_cmp(asm, opnd0);
519513
let split_right = split_shifted_immediate(asm, *right);
520514
let opnd1 = match split_right {
521-
Opnd::InsnOut { .. } if opnd0.num_bits() != split_right.num_bits() => {
515+
Opnd::VReg { .. } if opnd0.num_bits() != split_right.num_bits() => {
522516
split_right.with_num_bits(opnd0.num_bits().unwrap()).unwrap()
523517
},
524518
_ => split_right
@@ -560,13 +554,12 @@ impl Assembler
560554
*truthy = opnd0;
561555
*falsy = opnd1;
562556
// Merge `csel` and `mov` into a single `csel` when possible
563-
match iterator.peek() {
557+
match iterator.peek().map(|(_, insn)| insn) {
564558
Some(Insn::Mov { dest: Opnd::Reg(reg), src })
565-
if matches!(out, Opnd::InsnOut { .. }) && *out == *src && live_ranges[index] == index + 1 => {
559+
if matches!(out, Opnd::VReg { .. }) && *out == *src && live_ranges[out.vreg_idx()].end() == index + 1 => {
566560
*out = Opnd::Reg(*reg);
567561
asm.push_insn(insn);
568-
iterator.map_insn_index(asm);
569-
iterator.next_unmapped(); // Pop merged Insn::Mov
562+
iterator.next(); // Pop merged Insn::Mov
570563
}
571564
_ => {
572565
asm.push_insn(insn);
@@ -597,19 +590,19 @@ impl Assembler
597590
};
598591
asm.push_insn(insn);
599592
},
600-
Insn::LoadSExt { opnd, .. } => {
593+
Insn::LoadSExt { opnd, out } => {
601594
match opnd {
602595
// We only want to sign extend if the operand is a
603596
// register, instruction output, or memory address that
604597
// is 32 bits. Otherwise we'll just load the value
605598
// directly since there's no need to sign extend.
606599
Opnd::Reg(Reg { num_bits: 32, .. }) |
607-
Opnd::InsnOut { num_bits: 32, .. } |
600+
Opnd::VReg { num_bits: 32, .. } |
608601
Opnd::Mem(Mem { num_bits: 32, .. }) => {
609-
asm.load_sext(*opnd);
602+
asm.push_insn(insn);
610603
},
611604
_ => {
612-
asm.load(*opnd);
605+
asm.push_insn(Insn::Load { opnd: *opnd, out: *out });
613606
}
614607
};
615608
},
@@ -657,12 +650,11 @@ impl Assembler
657650
Insn::Not { opnd, .. } => {
658651
// The value that is being negated must be in a register, so
659652
// if we get anything else we need to load it first.
660-
let opnd0 = match opnd {
653+
*opnd = match opnd {
661654
Opnd::Mem(_) => split_load_operand(asm, *opnd),
662655
_ => *opnd
663656
};
664-
665-
asm.not(opnd0);
657+
asm.push_insn(insn);
666658
},
667659
Insn::LShift { opnd, .. } |
668660
Insn::RShift { opnd, .. } |
@@ -703,14 +695,14 @@ impl Assembler
703695
}
704696
},
705697
Insn::Sub { left, right, .. } => {
706-
let opnd0 = split_load_operand(asm, *left);
707-
let opnd1 = split_shifted_immediate(asm, *right);
708-
asm.sub(opnd0, opnd1);
698+
*left = split_load_operand(asm, *left);
699+
*right = split_shifted_immediate(asm, *right);
700+
asm.push_insn(insn);
709701
},
710702
Insn::Mul { left, right, .. } => {
711-
let opnd0 = split_load_operand(asm, *left);
712-
let opnd1 = split_load_operand(asm, *right);
713-
asm.mul(opnd0, opnd1);
703+
*left = split_load_operand(asm, *left);
704+
*right = split_load_operand(asm, *right);
705+
asm.push_insn(insn);
714706
},
715707
Insn::Test { left, right } => {
716708
// The value being tested must be in a register, so if it's
@@ -725,19 +717,9 @@ impl Assembler
725717
asm.test(opnd0, opnd1);
726718
},
727719
_ => {
728-
// If we have an output operand, then we need to replace it
729-
// with a new output operand from the new assembler.
730-
if insn.out_opnd().is_some() {
731-
let out_num_bits = Opnd::match_num_bits_iter(insn.opnd_iter());
732-
let out = insn.out_opnd_mut().unwrap();
733-
*out = asm.next_opnd_out(out_num_bits);
734-
}
735-
736720
asm.push_insn(insn);
737721
}
738-
};
739-
740-
iterator.map_insn_index(asm);
722+
}
741723
}
742724

743725
asm_local
@@ -1015,7 +997,7 @@ impl Assembler
1015997
Insn::Load { opnd, out } |
1016998
Insn::LoadInto { opnd, dest: out } => {
1017999
match *opnd {
1018-
Opnd::Reg(_) | Opnd::InsnOut { .. } => {
1000+
Opnd::Reg(_) | Opnd::VReg { .. } => {
10191001
mov(cb, out.into(), opnd.into());
10201002
},
10211003
Opnd::UImm(uimm) => {
@@ -1063,7 +1045,7 @@ impl Assembler
10631045
Insn::LoadSExt { opnd, out } => {
10641046
match *opnd {
10651047
Opnd::Reg(Reg { num_bits: 32, .. }) |
1066-
Opnd::InsnOut { num_bits: 32, .. } => {
1048+
Opnd::VReg { num_bits: 32, .. } => {
10671049
sxtw(cb, out.into(), opnd.into());
10681050
},
10691051
Opnd::Mem(Mem { num_bits: 32, .. }) => {

0 commit comments

Comments
 (0)