Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc_trans: take into account primitives larger than 8 bytes. #47437

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 43 additions & 55 deletions src/librustc_trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ use context::CodegenCx;

use rustc::ty::layout::{self, TyLayout, Size};

#[derive(Clone, Copy, PartialEq, Debug)]
/// Classification of "eightbyte" components.
// NB: the order of the variants is from general to specific,
// such that `unify(a, b)` is the "smaller" of `a` and `b`.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
enum Class {
None,
Int,
Sse,
SseUp
Expand All @@ -32,29 +34,10 @@ const LARGEST_VECTOR_SIZE: usize = 512;
const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;

fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
-> Result<[Class; MAX_EIGHTBYTES], Memory> {
fn unify(cls: &mut [Class],
off: Size,
c: Class) {
let i = (off.bytes() / 8) as usize;
let to_write = match (cls[i], c) {
(Class::None, _) => c,
(_, Class::None) => return,

(Class::Int, _) |
(_, Class::Int) => Class::Int,

(Class::Sse, _) |
(_, Class::Sse) => Class::Sse,

(Class::SseUp, Class::SseUp) => Class::SseUp
};
cls[i] = to_write;
}

-> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> {
fn classify<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
layout: TyLayout<'tcx>,
cls: &mut [Class],
cls: &mut [Option<Class>],
off: Size)
-> Result<(), Memory> {
if !off.is_abi_aligned(layout.align) {
Expand All @@ -64,31 +47,20 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
return Ok(());
}

match layout.abi {
layout::Abi::Uninhabited => {}
let mut c = match layout.abi {
layout::Abi::Uninhabited => return Ok(()),

layout::Abi::Scalar(ref scalar) => {
let reg = match scalar.value {
match scalar.value {
layout::Int(..) |
layout::Pointer => Class::Int,
layout::F32 |
layout::F64 => Class::Sse
};
unify(cls, off, reg);
}

layout::Abi::Vector { ref element, count } => {
unify(cls, off, Class::Sse);

// everything after the first one is the upper
// half of a register.
let stride = element.value.size(cx);
for i in 1..count {
let field_off = off + stride * i;
unify(cls, field_off, Class::SseUp);
}
}

layout::Abi::Vector { .. } => Class::Sse,

layout::Abi::ScalarPair(..) |
layout::Abi::Aggregate { .. } => {
match layout.variants {
Expand All @@ -97,12 +69,26 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
let field_off = off + layout.fields.offset(i);
classify(cx, layout.field(cx, i), cls, field_off)?;
}
return Ok(());
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => return Err(Memory),
}
}

};

// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
let first = (off.bytes() / 8) as usize;
let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
for cls in &mut cls[first..=last] {
*cls = Some(cls.map_or(c, |old| old.min(c)));

// Everything after the first Sse "eightbyte"
// component is the upper half of a register.
if c == Class::Sse {
c = Class::SseUp;
}
}

Ok(())
Expand All @@ -113,23 +99,23 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
return Err(Memory);
}

let mut cls = [Class::None; MAX_EIGHTBYTES];
let mut cls = [None; MAX_EIGHTBYTES];
classify(cx, arg.layout, &mut cls, Size::from_bytes(0))?;
if n > 2 {
if cls[0] != Class::Sse {
if cls[0] != Some(Class::Sse) {
return Err(Memory);
}
if cls[1..n].iter().any(|&c| c != Class::SseUp) {
if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
return Err(Memory);
}
} else {
let mut i = 0;
while i < n {
if cls[i] == Class::SseUp {
cls[i] = Class::Sse;
} else if cls[i] == Class::Sse {
if cls[i] == Some(Class::SseUp) {
cls[i] = Some(Class::Sse);
} else if cls[i] == Some(Class::Sse) {
i += 1;
while i != n && cls[i] == Class::SseUp { i += 1; }
while i != n && cls[i] == Some(Class::SseUp) { i += 1; }
} else {
i += 1;
}
Expand All @@ -139,14 +125,14 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
Ok(cls)
}

fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> {
if *i >= cls.len() {
return None;
}

match cls[*i] {
Class::None => None,
Class::Int => {
None => None,
Some(Class::Int) => {
*i += 1;
Some(match size.bytes() {
1 => Reg::i8(),
Expand All @@ -156,8 +142,10 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
_ => Reg::i64()
})
}
Class::Sse => {
let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
Some(Class::Sse) => {
let vec_len = 1 + cls[*i+1..].iter()
.take_while(|&&c| c == Some(Class::SseUp))
.count();
*i += vec_len;
Some(if vec_len == 1 {
match size.bytes() {
Expand All @@ -171,11 +159,11 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
}
})
}
c => bug!("reg_component: unhandled class {:?}", c)
Some(c) => bug!("reg_component: unhandled class {:?}", c)
}
}

fn cast_target(cls: &[Class], size: Size) -> CastTarget {
fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
let mut i = 0;
let lo = reg_component(cls, &mut i, size).unwrap();
let offset = Size::from_bytes(8) * (i as u64);
Expand Down Expand Up @@ -203,8 +191,8 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tc
Ok(ref cls) if is_arg => {
for &c in cls {
match c {
Class::Int => needed_int += 1,
Class::Sse => needed_sse += 1,
Some(Class::Int) => needed_int += 1,
Some(Class::Sse) => needed_sse += 1,
_ => {}
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/test/run-pass/issue-38763.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-emscripten

#![feature(i128_type)]

#[repr(C)]
pub struct Foo(i128);

#[no_mangle]
pub extern "C" fn foo(x: Foo) -> Foo { x }

fn main() {
foo(Foo(1));
}