ISLE: Migrate call and return instructions (#3785)

This adds infrastructure to allow implementing call and return
instructions in ISLE, and migrates the s390x back-end.

To implement ABI details, this patch creates public accessors
for `ABISig` and makes them accessible in ISLE.  All actual
code generation is then done in ISLE rules, following the
information provided by that signature.

[ Note that the s390x back end never requires multiple slots for
a single argument - the infrastructure to handle this should
already be present, however. ]

To implement loops in ISLE rules, this patch uses regular tail
recursion, employing a `Range` data structure holding a range
of integers to be looped over.
This commit is contained in:
Ulrich Weigand
2022-06-29 23:22:50 +02:00
committed by GitHub
parent 688168b4d7
commit 7a9479f77c
9 changed files with 566 additions and 184 deletions

View File

@@ -28,13 +28,6 @@ fn sign_extend_to_u64(value: u64, from_bits: u8) -> u64 {
}
}
/// Lower an instruction input to a reg.
fn put_input_in_reg<C: LowerCtx<I = Inst>>(ctx: &mut C, input: InsnInput) -> Reg {
ctx.put_input_in_regs(input.insn, input.input)
.only_reg()
.unwrap()
}
//=============================================================================
// Lowering: comparisons
@@ -69,9 +62,6 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
isa_flags: &s390x_settings::Flags,
) -> CodegenResult<()> {
let op = ctx.data(insn).opcode();
let inputs: SmallVec<[InsnInput; 4]> = (0..ctx.num_inputs(insn))
.map(|i| InsnInput { insn, input: i })
.collect();
let outputs: SmallVec<[InsnOutput; 2]> = (0..ctx.num_outputs(insn))
.map(|i| InsnOutput { insn, output: i })
.collect();
@@ -190,6 +180,10 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
| Opcode::ResumableTrapnz
| Opcode::Trapif
| Opcode::Debugtrap
| Opcode::Call
| Opcode::CallIndirect
| Opcode::FallthroughReturn
| Opcode::Return
| Opcode::StackAddr
| Opcode::FuncAddr
| Opcode::SymbolValue => implemented_in_isle(),
@@ -227,56 +221,6 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
unimplemented!("Pinned register support not implemented!");
}
Opcode::Call | Opcode::CallIndirect => {
let caller_conv = ctx.abi().call_conv();
let (mut abi, inputs) = match op {
Opcode::Call => {
let (extname, dist) = ctx.call_target(insn).unwrap();
let extname = extname.clone();
let sig = ctx.call_sig(insn).unwrap();
assert!(inputs.len() == sig.params.len());
assert!(outputs.len() == sig.returns.len());
(
S390xABICaller::from_func(sig, &extname, dist, caller_conv, flags)?,
&inputs[..],
)
}
Opcode::CallIndirect => {
let ptr = put_input_in_reg(ctx, inputs[0]);
let sig = ctx.call_sig(insn).unwrap();
assert!(inputs.len() - 1 == sig.params.len());
assert!(outputs.len() == sig.returns.len());
(
S390xABICaller::from_ptr(sig, ptr, op, caller_conv, flags)?,
&inputs[1..],
)
}
_ => unreachable!(),
};
assert!(inputs.len() == abi.num_args());
for (i, input) in inputs.iter().enumerate() {
let arg_reg = put_input_in_reg(ctx, *input);
abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(arg_reg));
}
abi.emit_call(ctx);
for (i, output) in outputs.iter().enumerate() {
let retval_reg = get_output_reg(ctx, *output).only_reg().unwrap();
abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(retval_reg));
}
abi.accumulate_outgoing_args_size(ctx);
}
Opcode::FallthroughReturn | Opcode::Return => {
for (i, input) in inputs.iter().enumerate() {
let reg = put_input_in_reg(ctx, *input);
let retval_reg = ctx.retval(i).only_reg().unwrap();
let ty = ctx.input_ty(insn, i);
ctx.emit(Inst::gen_move(retval_reg, reg, ty));
}
// N.B.: the Ret itself is generated by the ABI.
}
Opcode::RawBitcast
| Opcode::Splat
| Opcode::Swizzle