s390x: Support both big- and little-endian vector lane order (#4682)

This implements the s390x back-end portion of the solution for
https://github.com/bytecodealliance/wasmtime/issues/4566

We now support both big- and little-endian vector lane order
in code generation.  The order used for a function is determined
by the function's ABI: if it uses a Wasmtime ABI, it will use
little-endian lane order, and big-endian lane order otherwise.
(This ensures that all raw_bitcast instructions generated by
both wasmtime and other cranelift frontends can always be
implemented as a no-op.)

Lane order affects the implementation of a number of operations:
- Vector immediates
- Vector memory load / store (in big- and little-endian variants)
- Operations explicitly using lane numbers
  (insertlane, extractlane, shuffle, swizzle)
- Operations implicitly using lane numbers
  (iadd_pairwise, narrow/widen, promote/demote, fcvt_low, vhigh_bits)

In addition, when calling a function using a different lane order,
we need to lane-swap all vector values passed or returned in registers.

A small number of changes to common code were also needed:

- Ensure we always select a Wasmtime calling convention on s390x
  in crates/cranelift (func_signature).

- Fix vector immediates for filetests/runtests.  In PR #4427,
  I attempted to fix this by byte-swapping the V128 value, but
  with the new scheme, we'd instead need to perform a per-lane
  byte swap.  Since we do not know the actual type in write_to_slice
  and read_from_slice, this isn't easily possible.

  Revert this part of PR #4427 again, and instead just mark the
  memory buffer as little-endian when emitting the trampoline;
  the back-end will then emit correct code to load the constant.

- Change a runtest in simd-bitselect-to-vselect.clif to no longer
  make little-endian lane order assumptions.

- Remove runtests in simd-swizzle.clif that make little-endian
  lane order assumptions by relying on implicit type conversion
  when using a non-i16x8 swizzle result type (this feature should
  probably be removed anyway).

Tested with both wasmtime and cg_clif.
This commit is contained in:
Ulrich Weigand
2022-08-11 21:10:46 +02:00
committed by GitHub
parent c1c48b4386
commit 67870d1518
29 changed files with 6584 additions and 593 deletions

View File

@@ -2839,24 +2839,50 @@ impl MachInstEmit for Inst {
inst.emit(&[], sink, emit_info, state);
}
&Inst::VecLoad { rd, ref mem } | &Inst::VecLoadRev { rd, ref mem } => {
&Inst::VecLoad { rd, ref mem }
| &Inst::VecLoadRev { rd, ref mem }
| &Inst::VecLoadByte16Rev { rd, ref mem }
| &Inst::VecLoadByte32Rev { rd, ref mem }
| &Inst::VecLoadByte64Rev { rd, ref mem }
| &Inst::VecLoadElt16Rev { rd, ref mem }
| &Inst::VecLoadElt32Rev { rd, ref mem }
| &Inst::VecLoadElt64Rev { rd, ref mem } => {
let rd = allocs.next_writable(rd);
let mem = mem.with_allocs(&mut allocs);
let (opcode, m3) = match self {
&Inst::VecLoad { .. } => (0xe706, 0), // VL
&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ
&Inst::VecLoad { .. } => (0xe706, 0), // VL
&Inst::VecLoadRev { .. } => (0xe606, 4), // VLBRQ
&Inst::VecLoadByte16Rev { .. } => (0xe606, 1), // VLBRH
&Inst::VecLoadByte32Rev { .. } => (0xe606, 2), // VLBRF
&Inst::VecLoadByte64Rev { .. } => (0xe606, 3), // VLBRG
&Inst::VecLoadElt16Rev { .. } => (0xe607, 1), // VLERH
&Inst::VecLoadElt32Rev { .. } => (0xe607, 2), // VLERF
&Inst::VecLoadElt64Rev { .. } => (0xe607, 3), // VLERG
_ => unreachable!(),
};
mem_vrx_emit(rd.to_reg(), &mem, opcode, m3, true, sink, emit_info, state);
}
&Inst::VecStore { rd, ref mem } | &Inst::VecStoreRev { rd, ref mem } => {
&Inst::VecStore { rd, ref mem }
| &Inst::VecStoreRev { rd, ref mem }
| &Inst::VecStoreByte16Rev { rd, ref mem }
| &Inst::VecStoreByte32Rev { rd, ref mem }
| &Inst::VecStoreByte64Rev { rd, ref mem }
| &Inst::VecStoreElt16Rev { rd, ref mem }
| &Inst::VecStoreElt32Rev { rd, ref mem }
| &Inst::VecStoreElt64Rev { rd, ref mem } => {
let rd = allocs.next(rd);
let mem = mem.with_allocs(&mut allocs);
let (opcode, m3) = match self {
&Inst::VecStore { .. } => (0xe70e, 0), // VST
&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ
&Inst::VecStore { .. } => (0xe70e, 0), // VST
&Inst::VecStoreRev { .. } => (0xe60e, 4), // VSTBRQ
&Inst::VecStoreByte16Rev { .. } => (0xe60e, 1), // VSTBRH
&Inst::VecStoreByte32Rev { .. } => (0xe60e, 2), // VSTBRF
&Inst::VecStoreByte64Rev { .. } => (0xe60e, 3), // VSTBRG
&Inst::VecStoreElt16Rev { .. } => (0xe60f, 1), // VSTERH
&Inst::VecStoreElt32Rev { .. } => (0xe60f, 2), // VSTERF
&Inst::VecStoreElt64Rev { .. } => (0xe60f, 3), // VSTERG
_ => unreachable!(),
};
mem_vrx_emit(rd, &mem, opcode, m3, true, sink, emit_info, state);