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
@rustbot label O-SystemZ