Skip to content

Commit 4b3b5d4

Browse files
committed
s390x: Refactor branch and jumptable emission
The BranchTarget abstraction is no longer needed, since all branches are being emitted using a MachLabel target. Remove BranchTarget and simply use MachLabel everywhere a branch target is required. (This brings the s390x back-end in line with what x64 does as well.) In addition, simplify jumptable emission by moving all instructions that do not depend on the internal label (i.e. the conditional branch to the default label, as well as the scaling the index register) out of the combined JTSequence instruction. This refactoring will make moving branch generation to ISLE easier.
1 parent 881c194 commit 4b3b5d4

10 files changed

Lines changed: 730 additions & 873 deletions

File tree

cranelift/codegen/src/isa/s390x/inst.isle

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,15 +589,15 @@
589589

590590
;; An unconditional branch.
591591
(Jump
592-
(dest BranchTarget))
592+
(dest MachLabel))
593593

594594
;; A conditional branch. Contains two targets; at emission time, both are emitted, but
595595
;; the MachBuffer knows to truncate the trailing branch if fallthrough. We optimize the
596596
;; choice of taken/not_taken (inverting the branch polarity as needed) based on the
597597
;; fallthrough at the time of lowering.
598598
(CondBr
599-
(taken BranchTarget)
600-
(not_taken BranchTarget)
599+
(taken MachLabel)
600+
(not_taken MachLabel)
601601
(cond Cond))
602602

603603
;; A conditional trap execute a `Trap` if the condition is true. This is
@@ -624,7 +624,7 @@
624624
;;
625625
;; See, e.g., the lowering of `trapif` (conditional trap) for an example.
626626
(OneWayCondBr
627-
(target BranchTarget)
627+
(target MachLabel)
628628
(cond Cond))
629629

630630
;; An indirect branch through a register, augmented with set of all
@@ -644,10 +644,8 @@
644644
;; Jump-table sequence, as one compound instruction (see note in lower.rs
645645
;; for rationale).
646646
(JTSequence
647-
(info BoxJTSequenceInfo)
648647
(ridx Reg)
649-
(rtmp1 WritableReg)
650-
(rtmp2 WritableReg))
648+
(targets VecMachLabel))
651649

652650
;; Load an inline symbol reference with RelocDistance::Far.
653651
(LoadExtNameFar
@@ -680,8 +678,8 @@
680678

681679
(type BoxCallInfo (primitive BoxCallInfo))
682680
(type BoxCallIndInfo (primitive BoxCallIndInfo))
681+
(type MachLabel (primitive MachLabel))
683682
(type VecMachLabel (primitive VecMachLabel))
684-
(type BranchTarget (primitive BranchTarget))
685683
(type BoxJTSequenceInfo (primitive BoxJTSequenceInfo))
686684
(type BoxExternalName (primitive BoxExternalName))
687685
(type ValueLabel (primitive ValueLabel))

cranelift/codegen/src/isa/s390x/inst/args.rs

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub enum MemArg {
3838
},
3939

4040
/// PC-relative Reference to a label.
41-
Label { target: BranchTarget },
41+
Label { target: MachLabel },
4242

4343
/// PC-relative Reference to a near symbol.
4444
Symbol {
@@ -182,47 +182,6 @@ impl Cond {
182182
}
183183
}
184184

185-
/// A branch target. Either unresolved (basic-block index) or resolved (offset
186-
/// from end of current instruction).
187-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
188-
pub enum BranchTarget {
189-
/// An unresolved reference to a Label, as passed into
190-
/// `lower_branch_group()`.
191-
Label(MachLabel),
192-
/// A fixed PC offset.
193-
ResolvedOffset(i32),
194-
}
195-
196-
impl BranchTarget {
197-
/// Return the target's label, if it is a label-based target.
198-
pub fn as_label(self) -> Option<MachLabel> {
199-
match self {
200-
BranchTarget::Label(l) => Some(l),
201-
_ => None,
202-
}
203-
}
204-
205-
/// Return the target's offset, if specified, or zero if label-based.
206-
pub fn as_ri_offset_or_zero(self) -> u16 {
207-
let off = match self {
208-
BranchTarget::ResolvedOffset(off) => off >> 1,
209-
_ => 0,
210-
};
211-
assert!(off <= 0x7fff);
212-
assert!(off >= -0x8000);
213-
off as u16
214-
}
215-
216-
/// Return the target's offset, if specified, or zero if label-based.
217-
pub fn as_ril_offset_or_zero(self) -> u32 {
218-
let off = match self {
219-
BranchTarget::ResolvedOffset(off) => off >> 1,
220-
_ => 0,
221-
};
222-
off as u32
223-
}
224-
}
225-
226185
impl PrettyPrint for MemArg {
227186
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
228187
match self {
@@ -270,7 +229,7 @@ impl PrettyPrint for MemArg {
270229
}
271230
}
272231
}
273-
&MemArg::Label { ref target } => target.show_rru(mb_rru),
232+
&MemArg::Label { target } => target.to_string(),
274233
&MemArg::Symbol {
275234
ref name, offset, ..
276235
} => format!("{} + {}", name, offset),
@@ -306,12 +265,3 @@ impl PrettyPrint for Cond {
306265
s.to_string()
307266
}
308267
}
309-
310-
impl PrettyPrint for BranchTarget {
311-
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
312-
match self {
313-
&BranchTarget::Label(label) => format!("label{:?}", label.get()),
314-
&BranchTarget::ResolvedOffset(off) => format!("{}", off),
315-
}
316-
}
317-
}

cranelift/codegen/src/isa/s390x/inst/emit.rs

Lines changed: 35 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! S390x ISA: binary code emission.
22
33
use crate::binemit::{Reloc, StackMap};
4-
use crate::ir::condcodes::IntCC;
54
use crate::ir::MemFlags;
65
use crate::ir::{SourceLoc, TrapCode};
76
use crate::isa::s390x::inst::*;
@@ -153,14 +152,9 @@ pub fn mem_emit(
153152
&enc_rxy(opcode_rxy.unwrap(), rd, base, index, disp.bits()),
154153
);
155154
}
156-
&MemArg::Label { ref target } => {
157-
if let Some(l) = target.as_label() {
158-
sink.use_label_at_offset(sink.cur_offset(), l, LabelUse::BranchRIL);
159-
}
160-
put(
161-
sink,
162-
&enc_ril_b(opcode_ril.unwrap(), rd, target.as_ril_offset_or_zero()),
163-
);
155+
&MemArg::Label { target } => {
156+
sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);
157+
put(sink, &enc_ril_b(opcode_ril.unwrap(), rd, 0));
164158
}
165159
&MemArg::Symbol {
166160
ref name, offset, ..
@@ -1904,60 +1898,43 @@ impl MachInstEmit for Inst {
19041898
&Inst::EpiloguePlaceholder => {
19051899
// Noop; this is just a placeholder for epilogues.
19061900
}
1907-
&Inst::Jump { ref dest } => {
1901+
&Inst::Jump { dest } => {
19081902
let off = sink.cur_offset();
19091903
// Indicate that the jump uses a label, if so, so that a fixup can occur later.
1910-
if let Some(l) = dest.as_label() {
1911-
sink.use_label_at_offset(off, l, LabelUse::BranchRIL);
1912-
sink.add_uncond_branch(off, off + 6, l);
1913-
}
1904+
sink.use_label_at_offset(off, dest, LabelUse::BranchRIL);
1905+
sink.add_uncond_branch(off, off + 6, dest);
19141906
// Emit the jump itself.
19151907
let opcode = 0xc04; // BCRL
1916-
put(sink, &enc_ril_c(opcode, 15, dest.as_ril_offset_or_zero()));
1908+
put(sink, &enc_ril_c(opcode, 15, 0));
19171909
}
19181910
&Inst::IndirectBr { rn, .. } => {
19191911
let opcode = 0x07; // BCR
19201912
put(sink, &enc_rr(opcode, gpr(15), rn));
19211913
}
19221914
&Inst::CondBr {
1923-
ref taken,
1924-
ref not_taken,
1915+
taken,
1916+
not_taken,
19251917
cond,
19261918
} => {
19271919
let opcode = 0xc04; // BCRL
19281920

19291921
// Conditional part first.
19301922
let cond_off = sink.cur_offset();
1931-
if let Some(l) = taken.as_label() {
1932-
sink.use_label_at_offset(cond_off, l, LabelUse::BranchRIL);
1933-
let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);
1934-
sink.add_cond_branch(cond_off, cond_off + 6, l, inverted);
1935-
}
1936-
put(
1937-
sink,
1938-
&enc_ril_c(opcode, cond.bits(), taken.as_ril_offset_or_zero()),
1939-
);
1923+
sink.use_label_at_offset(cond_off, taken, LabelUse::BranchRIL);
1924+
let inverted = &enc_ril_c(opcode, cond.invert().bits(), 0);
1925+
sink.add_cond_branch(cond_off, cond_off + 6, taken, inverted);
1926+
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
19401927

19411928
// Unconditional part next.
19421929
let uncond_off = sink.cur_offset();
1943-
if let Some(l) = not_taken.as_label() {
1944-
sink.use_label_at_offset(uncond_off, l, LabelUse::BranchRIL);
1945-
sink.add_uncond_branch(uncond_off, uncond_off + 6, l);
1946-
}
1947-
put(
1948-
sink,
1949-
&enc_ril_c(opcode, 15, not_taken.as_ril_offset_or_zero()),
1950-
);
1930+
sink.use_label_at_offset(uncond_off, not_taken, LabelUse::BranchRIL);
1931+
sink.add_uncond_branch(uncond_off, uncond_off + 6, not_taken);
1932+
put(sink, &enc_ril_c(opcode, 15, 0));
19511933
}
1952-
&Inst::OneWayCondBr { ref target, cond } => {
1934+
&Inst::OneWayCondBr { target, cond } => {
19531935
let opcode = 0xc04; // BCRL
1954-
if let Some(l) = target.as_label() {
1955-
sink.use_label_at_offset(sink.cur_offset(), l, LabelUse::BranchRIL);
1956-
}
1957-
put(
1958-
sink,
1959-
&enc_ril_c(opcode, cond.bits(), target.as_ril_offset_or_zero()),
1960-
);
1936+
sink.use_label_at_offset(sink.cur_offset(), target, LabelUse::BranchRIL);
1937+
put(sink, &enc_ril_c(opcode, cond.bits(), 0));
19611938
}
19621939
&Inst::Nop0 => {}
19631940
&Inst::Nop2 => {
@@ -1984,86 +1961,49 @@ impl MachInstEmit for Inst {
19841961
let srcloc = state.cur_srcloc();
19851962
put_with_trap(sink, &enc_e(0x0000), srcloc, trap_code);
19861963
}
1987-
&Inst::JTSequence {
1988-
ridx,
1989-
rtmp1,
1990-
rtmp2,
1991-
ref info,
1992-
..
1993-
} => {
1964+
&Inst::JTSequence { ridx, ref targets } => {
19941965
let table_label = sink.get_label();
19951966

19961967
// This sequence is *one* instruction in the vcode, and is expanded only here at
19971968
// emission time, because we cannot allow the regalloc to insert spills/reloads in
19981969
// the middle; we depend on hardcoded PC-rel addressing below.
19991970

2000-
// Bounds-check index and branch to default.
2001-
let inst = Inst::CmpRUImm32 {
2002-
op: CmpOp::CmpL64,
2003-
rn: ridx,
2004-
imm: info.targets.len() as u32,
2005-
};
2006-
inst.emit(sink, emit_info, state);
2007-
let inst = Inst::OneWayCondBr {
2008-
target: info.default_target,
2009-
cond: Cond::from_intcc(IntCC::UnsignedGreaterThanOrEqual),
2010-
};
2011-
inst.emit(sink, emit_info, state);
2012-
2013-
// Set rtmp2 to index scaled by entry size.
2014-
let inst = Inst::ShiftRR {
2015-
shift_op: ShiftOp::LShL64,
2016-
rd: rtmp2,
2017-
rn: ridx,
2018-
shift_imm: 2,
2019-
shift_reg: zero_reg(),
2020-
};
2021-
inst.emit(sink, emit_info, state);
2022-
2023-
// Set rtmp1 to address of jump table.
1971+
// Set temp register to address of jump table.
1972+
let rtmp = writable_spilltmp_reg();
20241973
let inst = Inst::LoadAddr {
2025-
rd: rtmp1,
1974+
rd: rtmp,
20261975
mem: MemArg::Label {
2027-
target: BranchTarget::Label(table_label),
1976+
target: table_label,
20281977
},
20291978
};
20301979
inst.emit(sink, emit_info, state);
20311980

2032-
// Set rtmp2 to value loaded out of jump table.
2033-
let inst = Inst::Load64SExt32 {
2034-
rd: rtmp2,
2035-
mem: MemArg::reg_plus_reg(rtmp1.to_reg(), rtmp2.to_reg(), MemFlags::trusted()),
2036-
};
2037-
inst.emit(sink, emit_info, state);
2038-
2039-
// Set rtmp1 to target address (rtmp1 + rtmp2).
2040-
let inst = Inst::AluRRR {
2041-
alu_op: ALUOp::Add64,
2042-
rd: rtmp1,
2043-
rn: rtmp1.to_reg(),
2044-
rm: rtmp2.to_reg(),
1981+
// Set temp to target address by adding the value of the jump table entry.
1982+
let inst = Inst::AluRX {
1983+
alu_op: ALUOp::Add64Ext32,
1984+
rd: rtmp,
1985+
mem: MemArg::reg_plus_reg(rtmp.to_reg(), ridx, MemFlags::trusted()),
20451986
};
20461987
inst.emit(sink, emit_info, state);
20471988

20481989
// Branch to computed address. (`targets` here is only used for successor queries
20491990
// and is not needed for emission.)
20501991
let inst = Inst::IndirectBr {
2051-
rn: rtmp1.to_reg(),
1992+
rn: rtmp.to_reg(),
20521993
targets: vec![],
20531994
};
20541995
inst.emit(sink, emit_info, state);
20551996

20561997
// Emit jump table (table of 32-bit offsets).
1998+
// The first entry is the default target, which is not emitted
1999+
// into the jump table, so we skip it here. It is only in the
2000+
// list so MachTerminator will see the potential target.
20572001
sink.bind_label(table_label);
20582002
let jt_off = sink.cur_offset();
2059-
for &target in info.targets.iter() {
2003+
for &target in targets.iter().skip(1) {
20602004
let word_off = sink.cur_offset();
20612005
let off_into_table = word_off - jt_off;
2062-
sink.use_label_at_offset(
2063-
word_off,
2064-
target.as_label().unwrap(),
2065-
LabelUse::PCRel32,
2066-
);
2006+
sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
20672007
sink.put4(off_into_table.swap_bytes());
20682008
}
20692009

0 commit comments

Comments
 (0)