Description
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
rust/compiler/rustc_codegen_llvm/src/abi.rs
Lines 121 to 135 in 39dc268
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:
rust/compiler/rustc_target/src/callconv/s390x.rs
Lines 40 to 43 in 39dc268
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