Skip to content

vector types are passed incorrectly on s390x #135744

Closed
@folkertdev

Description

@folkertdev

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)C-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeO-SystemZTarget: SystemZ processors (s390x)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions