Skip to content

Commit f1383ec

Browse files
authored
s390x: Add try_call / try_call_indirect support (#10557)
Following-up on #10510 this adds the corresponding support to the s390x target. Due to the separate ABI implementation, this currently needs to duplicate some of the underlying logic. I hope to be able to refactor ABI handling in the future to be able to share more of that code across all targets.
1 parent c453d95 commit f1383ec

File tree

8 files changed

+527
-84
lines changed

8 files changed

+527
-84
lines changed

cranelift/codegen/src/isa/s390x/abi.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,8 @@ impl ABIMachineSpec for S390xMachineDeps {
906906
call_conv_of_callee: isa::CallConv,
907907
is_exception: bool,
908908
) -> PRegSet {
909-
assert!(!is_exception);
910909
match call_conv_of_callee {
910+
_ if is_exception => ALL_CLOBBERS,
911911
isa::CallConv::Tail => TAIL_CLOBBERS,
912912
_ => SYSV_CLOBBERS,
913913
}
@@ -1009,6 +1009,14 @@ impl ABIMachineSpec for S390xMachineDeps {
10091009
fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
10101010
panic!("Should not be called");
10111011
}
1012+
1013+
fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
1014+
const PAYLOAD_REGS: &'static [Reg] = &[gpr(6), gpr(7)];
1015+
match call_conv {
1016+
isa::CallConv::SystemV | isa::CallConv::Tail => PAYLOAD_REGS,
1017+
_ => &[],
1018+
}
1019+
}
10121020
}
10131021

10141022
impl S390xMachineDeps {
@@ -1378,6 +1386,59 @@ const fn tail_clobbers() -> PRegSet {
13781386
}
13791387
const TAIL_CLOBBERS: PRegSet = tail_clobbers();
13801388

1389+
const fn all_clobbers() -> PRegSet {
1390+
PRegSet::empty()
1391+
.with(gpr_preg(0))
1392+
.with(gpr_preg(1))
1393+
.with(gpr_preg(2))
1394+
.with(gpr_preg(3))
1395+
.with(gpr_preg(4))
1396+
.with(gpr_preg(5))
1397+
.with(gpr_preg(6))
1398+
.with(gpr_preg(7))
1399+
.with(gpr_preg(8))
1400+
.with(gpr_preg(9))
1401+
.with(gpr_preg(10))
1402+
.with(gpr_preg(11))
1403+
.with(gpr_preg(12))
1404+
.with(gpr_preg(13))
1405+
.with(gpr_preg(14))
1406+
.with(gpr_preg(15))
1407+
.with(vr_preg(0))
1408+
.with(vr_preg(1))
1409+
.with(vr_preg(2))
1410+
.with(vr_preg(3))
1411+
.with(vr_preg(4))
1412+
.with(vr_preg(5))
1413+
.with(vr_preg(6))
1414+
.with(vr_preg(7))
1415+
.with(vr_preg(8))
1416+
.with(vr_preg(9))
1417+
.with(vr_preg(10))
1418+
.with(vr_preg(11))
1419+
.with(vr_preg(12))
1420+
.with(vr_preg(13))
1421+
.with(vr_preg(14))
1422+
.with(vr_preg(15))
1423+
.with(vr_preg(16))
1424+
.with(vr_preg(17))
1425+
.with(vr_preg(18))
1426+
.with(vr_preg(19))
1427+
.with(vr_preg(20))
1428+
.with(vr_preg(21))
1429+
.with(vr_preg(22))
1430+
.with(vr_preg(23))
1431+
.with(vr_preg(24))
1432+
.with(vr_preg(25))
1433+
.with(vr_preg(26))
1434+
.with(vr_preg(27))
1435+
.with(vr_preg(28))
1436+
.with(vr_preg(29))
1437+
.with(vr_preg(30))
1438+
.with(vr_preg(31))
1439+
}
1440+
const ALL_CLOBBERS: PRegSet = all_clobbers();
1441+
13811442
fn sysv_create_machine_env() -> MachineEnv {
13821443
MachineEnv {
13831444
preferred_regs_by_class: [

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

+15-6
Original file line numberDiff line numberDiff line change
@@ -2669,10 +2669,9 @@
26692669
dst))
26702670

26712671
;; Helper for emitting `MInst.Call` instructions.
2672-
(decl call_impl (WritableReg CallSiteInfo) InstOutput)
2673-
(rule (call_impl reg (call_site_info info output))
2674-
(let ((_ Unit (emit (MInst.Call reg info))))
2675-
output))
2672+
(decl call_impl (WritableReg BoxCallInfo) SideEffectNoResult)
2673+
(rule (call_impl reg info)
2674+
(SideEffectNoResult.Inst (MInst.Call reg info)))
26762675

26772676
;; Helper for emitting `MInst.ReturnCall` instructions.
26782677
(decl return_call_impl (BoxReturnCallInfo) SideEffectNoResult)
@@ -3478,6 +3477,9 @@
34783477
(decl abi_call_site_info (Sig CallInstDest CallArgList) CallSiteInfo)
34793478
(extern constructor abi_call_site_info abi_call_site_info)
34803479

3480+
(decl abi_try_call_info (Sig CallInstDest CallArgList ExceptionTable MachLabelSlice) BoxCallInfo)
3481+
(extern constructor abi_try_call_info abi_try_call_info)
3482+
34813483
(decl abi_return_call_info (Sig CallInstDest CallArgList) BoxReturnCallInfo)
34823484
(extern constructor abi_return_call_info abi_return_call_info)
34833485

@@ -3495,13 +3497,20 @@
34953497

34963498
(decl abi_call (Sig CallInstDest CallArgList) InstOutput)
34973499
(rule (abi_call abi dest uses)
3498-
(let ((info CallSiteInfo (abi_call_site_info abi dest uses)))
3499-
(call_impl (writable_link_reg) info)))
3500+
(abi_call_impl (abi_call_site_info abi dest uses)))
3501+
(decl abi_call_impl (CallSiteInfo) InstOutput)
3502+
(rule (abi_call_impl (call_site_info info output))
3503+
(let ((_ Unit (emit_side_effect (call_impl (writable_link_reg) info))))
3504+
output))
35003505

35013506
(decl abi_return_call (Sig CallInstDest CallArgList) SideEffectNoResult)
35023507
(rule (abi_return_call abi dest uses)
35033508
(return_call_impl (abi_return_call_info abi dest uses)))
35043509

3510+
(decl abi_try_call (Sig CallInstDest CallArgList ExceptionTable MachLabelSlice) SideEffectNoResult)
3511+
(rule (abi_try_call abi dest uses et targets)
3512+
(call_impl (writable_link_reg) (abi_try_call_info abi dest uses et targets)))
3513+
35053514
(decl abi_lane_order (Sig) LaneOrder)
35063515
(extern constructor abi_lane_order abi_lane_order)
35073516

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

+17
Original file line numberDiff line numberDiff line change
@@ -3218,11 +3218,28 @@ impl Inst {
32183218
put(sink, enc);
32193219
sink.add_call_site();
32203220

3221+
// Add exception info, if any, at this point (which will
3222+
// be the return address on stack).
3223+
if let Some(try_call) = info.try_call_info.as_ref() {
3224+
for &(tag, label) in &try_call.exception_dests {
3225+
sink.add_exception_handler(tag, label);
3226+
}
3227+
}
3228+
32213229
state.nominal_sp_offset -= info.callee_pop_size;
32223230

32233231
for inst in S390xMachineDeps::gen_retval_loads(info) {
32243232
inst.emit(sink, emit_info, state);
32253233
}
3234+
3235+
// If this is a try-call, jump to the continuation
3236+
// (normal-return) block.
3237+
if let Some(try_call) = info.try_call_info.as_ref() {
3238+
let jmp = Inst::Jump {
3239+
dest: try_call.continuation,
3240+
};
3241+
jmp.emit(sink, emit_info, state);
3242+
}
32263243
}
32273244
&Inst::ReturnCall { ref info } => {
32283245
let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(

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

+15-2
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,7 @@ impl MachInst for Inst {
10761076
&Inst::CondBr { .. } => MachTerminator::Branch,
10771077
&Inst::IndirectBr { .. } => MachTerminator::Branch,
10781078
&Inst::JTSequence { .. } => MachTerminator::Branch,
1079+
&Inst::Call { ref info, .. } if info.try_call_info.is_some() => MachTerminator::Branch,
10791080
_ => MachTerminator::None,
10801081
}
10811082
}
@@ -3119,18 +3120,30 @@ impl Inst {
31193120
if !retval_loads.is_empty() {
31203121
retval_loads = " ; ".to_string() + &retval_loads;
31213122
}
3123+
let try_call = if let Some(try_call_info) = &info.try_call_info {
3124+
let dests = try_call_info
3125+
.exception_dests
3126+
.iter()
3127+
.map(|(tag, label)| format!("{tag:?}: {label:?}"))
3128+
.collect::<Vec<_>>()
3129+
.join(", ");
3130+
format!("; jg {:?}; catch [{dests}]", try_call_info.continuation)
3131+
} else {
3132+
"".to_string()
3133+
};
31223134
let callee_pop_size = if info.callee_pop_size > 0 {
31233135
format!(" ; callee_pop_size {}", info.callee_pop_size)
31243136
} else {
31253137
"".to_string()
31263138
};
31273139
format!(
3128-
"{} {}, {}{}{}",
3140+
"{} {}, {}{}{}{}",
31293141
opcode,
31303142
show_reg(link),
31313143
dest,
31323144
callee_pop_size,
3133-
retval_loads
3145+
retval_loads,
3146+
try_call
31343147
)
31353148
}
31363149
&Inst::ReturnCall { ref info } => {

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::machinst::*;
1010
// Registers, the Universe thereof, and printing
1111

1212
/// Get a reference to a GPR (integer register).
13-
pub fn gpr(num: u8) -> Reg {
14-
Reg::from(gpr_preg(num))
13+
pub const fn gpr(num: u8) -> Reg {
14+
Reg::from_real_reg(gpr_preg(num))
1515
}
1616

1717
pub(crate) const fn gpr_preg(num: u8) -> PReg {
@@ -25,8 +25,8 @@ pub fn writable_gpr(num: u8) -> Writable<Reg> {
2525
}
2626

2727
/// Get a reference to a VR (vector register).
28-
pub fn vr(num: u8) -> Reg {
29-
Reg::from(vr_preg(num))
28+
pub const fn vr(num: u8) -> Reg {
29+
Reg::from_real_reg(vr_preg(num))
3030
}
3131

3232
pub(crate) const fn vr_preg(num: u8) -> PReg {

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

+24
Original file line numberDiff line numberDiff line change
@@ -3926,6 +3926,30 @@
39263926
(args_builder_finish uses)))
39273927

39283928

3929+
;;;; Rules for `try_call` and `try_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3930+
3931+
;; Direct call to an in-range function.
3932+
(rule 1 (lower_branch (try_call (func_ref_data sig_ref name (reloc_distance_near)) args et) targets)
3933+
(let ((abi Sig (abi_sig sig_ref))
3934+
(uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args)))
3935+
(emit_side_effect (abi_try_call abi (CallInstDest.Direct name) uses et targets))))
3936+
3937+
;; Direct call to an out-of-range function (implicitly via pointer).
3938+
(rule (lower_branch (try_call (func_ref_data sig_ref name _) args et) targets)
3939+
(let ((abi Sig (abi_sig sig_ref))
3940+
(uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args))
3941+
(target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0))))
3942+
(emit_side_effect (abi_try_call abi (CallInstDest.Indirect target) uses et targets))))
3943+
3944+
;; Indirect call.
3945+
(rule (lower_branch (try_call_indirect ptr args et) targets)
3946+
(if-let (exception_sig sig_ref) et)
3947+
(let ((abi Sig (abi_sig sig_ref))
3948+
(target Reg (put_in_reg ptr))
3949+
(uses CallArgList (lower_call_args abi (range 0 (abi_num_args abi)) args)))
3950+
(emit_side_effect (abi_try_call abi (CallInstDest.Indirect target) uses et targets))))
3951+
3952+
39293953
;;;; Common helpers for argument lowering ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
39303954

39313955
;; Lower function arguments (part 1): prepare buffer copies.

0 commit comments

Comments
 (0)