Skip to content

Commit

Permalink
rustc_trans: take into account primitives larger than 8 bytes.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Jan 16, 2018
1 parent da569fa commit cbeebc5
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 55 deletions.
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
21 changes: 21 additions & 0 deletions src/test/run-pass/issue-38763.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.

#![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));
}

0 comments on commit cbeebc5

Please sign in to comment.