vector types are passed incorrectly on s390x (original) (raw)

I tried this code:

#![feature(s390x_target_feature, portable_simd, simd_ffi, link_llvm_intrinsics)] use std::simd::*;

#[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.smax.v2i64"] fn vmxg(a: i64x2, b: i64x2) -> i64x2; }

#[no_mangle] #[target_feature(enable = "vector")] pub unsafe fn bar(a: i64x2, b: i64x2) -> i64x2 { vmxg(a, b) }

I expected to see this happen: the vmxg instruction is emitted

Instead, this happened: the vmxb instruction is emitted


I did some digging, and I think I have the problem, and maybe a solution.

The problem

https://godbolt.org/z/YxK3Eo66x

in the godbolt, we see that the llvm.smax.v2i64 function gets an incorrect signature

declare <2 x i64> @llvm.smax.v2i64(<16 x i8>, <16 x i8>) unnamed_addr #1

(we would expect this instead)

declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>) unnamed_addr #1

So, somewhere along the way, type information is lost.

Where the problem shows up

We first see the incorrect argument type here

impl LlvmType for Reg {
fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
match self.kind {
RegKind::Integer => cx.type_ix(self.size.bits()),
RegKind::Float => match self.size.bits() {
16 => cx.type_f16(),
32 => cx.type_f32(),
64 => cx.type_f64(),
128 => cx.type_f128(),
_ => bug!("unsupported float: {:?}", self),
},
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
}
}
}

The Reg type does not have enough information to recompute the element type of the vector, and hence it defaults to type_i8. That is wrong!

Why Reg

That Reg (with insufficient type information) is used because of this logic in the calling convention code:

let size = arg.layout.size;
if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) {
arg.cast_to(Reg { kind: RegKind::Vector, size });
return;

The PassMode for the arguments will be PassMode::Cast.

Solutions

I'm not (yet) familiar with the details of the s390x calling convention, so maybe this Cast has an essential function. But I think it would be fine to pass vector arguments using PassMode::Direct. That works for the example at hand anyway.

If not, then the element type information must be stored somewhere so that it can be retrieved later

cc @taiki-e @uweigand

@rustbot label O-SystemZ