Skip to content

Commit fe2fb24

Browse files
authored
Rollup merge of #47437 - eddyb:issue-38763, r=nagisa
rustc_trans: take into account primitives larger than 8 bytes. Fixes #38763 by marking all "eightbytes" covered by a primitive appropriately, not just the first.
2 parents 3b24033 + cbeebc5 commit fe2fb24

File tree

2 files changed

+64
-55
lines changed

2 files changed

+64
-55
lines changed

src/librustc_trans/cabi_x86_64.rs

+43-55
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ use context::CodegenCx;
1616

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

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

3436
fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
35-
-> Result<[Class; MAX_EIGHTBYTES], Memory> {
36-
fn unify(cls: &mut [Class],
37-
off: Size,
38-
c: Class) {
39-
let i = (off.bytes() / 8) as usize;
40-
let to_write = match (cls[i], c) {
41-
(Class::None, _) => c,
42-
(_, Class::None) => return,
43-
44-
(Class::Int, _) |
45-
(_, Class::Int) => Class::Int,
46-
47-
(Class::Sse, _) |
48-
(_, Class::Sse) => Class::Sse,
49-
50-
(Class::SseUp, Class::SseUp) => Class::SseUp
51-
};
52-
cls[i] = to_write;
53-
}
54-
37+
-> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> {
5538
fn classify<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
5639
layout: TyLayout<'tcx>,
57-
cls: &mut [Class],
40+
cls: &mut [Option<Class>],
5841
off: Size)
5942
-> Result<(), Memory> {
6043
if !off.is_abi_aligned(layout.align) {
@@ -64,31 +47,20 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
6447
return Ok(());
6548
}
6649

67-
match layout.abi {
68-
layout::Abi::Uninhabited => {}
50+
let mut c = match layout.abi {
51+
layout::Abi::Uninhabited => return Ok(()),
6952

7053
layout::Abi::Scalar(ref scalar) => {
71-
let reg = match scalar.value {
54+
match scalar.value {
7255
layout::Int(..) |
7356
layout::Pointer => Class::Int,
7457
layout::F32 |
7558
layout::F64 => Class::Sse
76-
};
77-
unify(cls, off, reg);
78-
}
79-
80-
layout::Abi::Vector { ref element, count } => {
81-
unify(cls, off, Class::Sse);
82-
83-
// everything after the first one is the upper
84-
// half of a register.
85-
let stride = element.value.size(cx);
86-
for i in 1..count {
87-
let field_off = off + stride * i;
88-
unify(cls, field_off, Class::SseUp);
8959
}
9060
}
9161

62+
layout::Abi::Vector { .. } => Class::Sse,
63+
9264
layout::Abi::ScalarPair(..) |
9365
layout::Abi::Aggregate { .. } => {
9466
match layout.variants {
@@ -97,12 +69,26 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
9769
let field_off = off + layout.fields.offset(i);
9870
classify(cx, layout.field(cx, i), cls, field_off)?;
9971
}
72+
return Ok(());
10073
}
10174
layout::Variants::Tagged { .. } |
10275
layout::Variants::NicheFilling { .. } => return Err(Memory),
10376
}
10477
}
10578

79+
};
80+
81+
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
82+
let first = (off.bytes() / 8) as usize;
83+
let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
84+
for cls in &mut cls[first..=last] {
85+
*cls = Some(cls.map_or(c, |old| old.min(c)));
86+
87+
// Everything after the first Sse "eightbyte"
88+
// component is the upper half of a register.
89+
if c == Class::Sse {
90+
c = Class::SseUp;
91+
}
10692
}
10793

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

116-
let mut cls = [Class::None; MAX_EIGHTBYTES];
102+
let mut cls = [None; MAX_EIGHTBYTES];
117103
classify(cx, arg.layout, &mut cls, Size::from_bytes(0))?;
118104
if n > 2 {
119-
if cls[0] != Class::Sse {
105+
if cls[0] != Some(Class::Sse) {
120106
return Err(Memory);
121107
}
122-
if cls[1..n].iter().any(|&c| c != Class::SseUp) {
108+
if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
123109
return Err(Memory);
124110
}
125111
} else {
126112
let mut i = 0;
127113
while i < n {
128-
if cls[i] == Class::SseUp {
129-
cls[i] = Class::Sse;
130-
} else if cls[i] == Class::Sse {
114+
if cls[i] == Some(Class::SseUp) {
115+
cls[i] = Some(Class::Sse);
116+
} else if cls[i] == Some(Class::Sse) {
131117
i += 1;
132-
while i != n && cls[i] == Class::SseUp { i += 1; }
118+
while i != n && cls[i] == Some(Class::SseUp) { i += 1; }
133119
} else {
134120
i += 1;
135121
}
@@ -139,14 +125,14 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
139125
Ok(cls)
140126
}
141127

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

147133
match cls[*i] {
148-
Class::None => None,
149-
Class::Int => {
134+
None => None,
135+
Some(Class::Int) => {
150136
*i += 1;
151137
Some(match size.bytes() {
152138
1 => Reg::i8(),
@@ -156,8 +142,10 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
156142
_ => Reg::i64()
157143
})
158144
}
159-
Class::Sse => {
160-
let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
145+
Some(Class::Sse) => {
146+
let vec_len = 1 + cls[*i+1..].iter()
147+
.take_while(|&&c| c == Some(Class::SseUp))
148+
.count();
161149
*i += vec_len;
162150
Some(if vec_len == 1 {
163151
match size.bytes() {
@@ -171,11 +159,11 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
171159
}
172160
})
173161
}
174-
c => bug!("reg_component: unhandled class {:?}", c)
162+
Some(c) => bug!("reg_component: unhandled class {:?}", c)
175163
}
176164
}
177165

178-
fn cast_target(cls: &[Class], size: Size) -> CastTarget {
166+
fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
179167
let mut i = 0;
180168
let lo = reg_component(cls, &mut i, size).unwrap();
181169
let offset = Size::from_bytes(8) * (i as u64);
@@ -203,8 +191,8 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tc
203191
Ok(ref cls) if is_arg => {
204192
for &c in cls {
205193
match c {
206-
Class::Int => needed_int += 1,
207-
Class::Sse => needed_sse += 1,
194+
Some(Class::Int) => needed_int += 1,
195+
Some(Class::Sse) => needed_sse += 1,
208196
_ => {}
209197
}
210198
}

src/test/run-pass/issue-38763.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(i128_type)]
12+
13+
#[repr(C)]
14+
pub struct Foo(i128);
15+
16+
#[no_mangle]
17+
pub extern "C" fn foo(x: Foo) -> Foo { x }
18+
19+
fn main() {
20+
foo(Foo(1));
21+
}

0 commit comments

Comments
 (0)