Skip to content

Commit

Permalink
Rollup merge of rust-lang#41206 - eddyb:avoid-illegal-vectors, r=nagisa
Browse files Browse the repository at this point in the history
Fix pairs of doubles using an illegal <8 x i8> vector.

Accidentally introduced in rust-lang#40658 and discovered in some Objective-C bindings (returning `NSPoint`).
Turns out LLVM will widen element types of illegal vectors instead of increasing element count, i.e. it will zero-extend `<8 x i8>` to `<8 x i16>`, interleaving the bytes, instead of using the first 8 of `<16 x i8>`.
  • Loading branch information
TimNN authored Apr 12, 2017
2 parents afb300d + 0303a33 commit 092f19a
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/librustc_trans/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {

Layout::Vector { .. } => {
Some(Reg {
kind: RegKind::Integer,
kind: RegKind::Vector,
size: self.size(ccx)
})
}
Expand Down
17 changes: 9 additions & 8 deletions src/librustc_trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,15 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
Class::Sse => {
let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
*i += vec_len;
Some(match size {
4 => Reg::f32(),
8 => Reg::f64(),
_ => {
Reg {
kind: RegKind::Vector,
size: Size::from_bytes(vec_len as u64 * 8)
}
Some(if vec_len == 1 {
match size {
4 => Reg::f32(),
_ => Reg::f64()
}
} else {
Reg {
kind: RegKind::Vector,
size: Size::from_bytes(vec_len as u64 * 8)
}
})
}
Expand Down
19 changes: 19 additions & 0 deletions src/test/run-make/extern-fn-struct-passing-abi/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ struct Huge {
int32_t e;
};

struct FloatPoint {
double x;
double y;
};

// System V x86_64 ABI:
// a, b, c, d, e should be in registers
// s should be byval pointer
Expand Down Expand Up @@ -258,3 +263,17 @@ struct Huge huge_struct(struct Huge s) {

return s;
}

// System V x86_64 ABI:
// p should be in registers
// return should be in registers
//
// Win64 ABI:
// p should be a byval pointer
// return should be in a hidden sret pointer
struct FloatPoint float_point(struct FloatPoint p) {
assert(p.x == 5.);
assert(p.y == -3.);

return p;
}
11 changes: 11 additions & 0 deletions src/test/run-make/extern-fn-struct-passing-abi/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ struct Huge {
e: i32
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
struct FloatPoint {
x: f64,
y: f64
}

#[link(name = "test", kind = "static")]
extern {
fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
Expand All @@ -72,13 +79,16 @@ extern {
fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;

fn huge_struct(s: Huge) -> Huge;

fn float_point(p: FloatPoint) -> FloatPoint;
}

fn main() {
let s = Rect { a: 553, b: 554, c: 555, d: 556 };
let t = BiggerRect { s: s, a: 27834, b: 7657 };
let u = FloatRect { a: 3489, b: 3490, c: 8. };
let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
let p = FloatPoint { x: 5., y: -3. };

unsafe {
byval_rect(1, 2, 3, 4, 5, s);
Expand All @@ -94,5 +104,6 @@ fn main() {
assert_eq!(split_ret_byval_struct(1, 2, s), s);
assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
assert_eq!(sret_split_struct(1, 2, s), t);
assert_eq!(float_point(p), p);
}
}

0 comments on commit 092f19a

Please sign in to comment.