From 2be697bc215f19b4bf17df6b9b56626ab7b1d994 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 3 Jan 2018 17:43:30 +0100 Subject: Implement repr(transparent) --- src/test/codegen/repr-transparent-aggregates-1.rs | 53 +++++++ src/test/codegen/repr-transparent-aggregates-2.rs | 54 +++++++ src/test/codegen/repr-transparent.rs | 177 ++++++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 src/test/codegen/repr-transparent-aggregates-1.rs create mode 100644 src/test/codegen/repr-transparent-aggregates-2.rs create mode 100644 src/test/codegen/repr-transparent.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs new file mode 100644 index 00000000000..2eeed2b788c --- /dev/null +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -0,0 +1,53 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +// ignore-arm +// ignore-mips +// ignore-mips64 +// ignore-powerpc +// ignore-powerpc64 +// See repr-transparent.rs + +#![crate_type="lib"] +#![feature(repr_transparent)] + + +#[repr(C)] +pub struct Big([u32; 16]); + +#[repr(transparent)] +pub struct BigW(Big); + +// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], %Big* [[BIG_ARG_ATTRS:.*]]) +#[no_mangle] +pub extern fn test_Big(_: Big) -> Big { loop {} } + +// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], %BigW* [[BIG_ARG_ATTRS]]) +#[no_mangle] +pub extern fn test_BigW(_: BigW) -> BigW { loop {} } + + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct BigUw(BigU); + +// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS:.*]]) +#[no_mangle] +pub extern fn test_BigU(_: BigU) -> BigU { loop {} } + +// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], %BigUw* [[BIGU_ARG_ATTRS]]) +#[no_mangle] +pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs new file mode 100644 index 00000000000..e6374928a5c --- /dev/null +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -0,0 +1,54 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +// ignore-aarch64 +// ignore-asmjs +// ignore-s390x +// ignore-wasm +// ignore-x86 +// ignore-x86_64 +// See repr-transparent.rs + +#![crate_type="lib"] +#![feature(repr_transparent)] + + +#[repr(C)] +pub struct Big([u32; 16]); + +#[repr(transparent)] +pub struct BigW(Big); + +// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [16 x i32] +#[no_mangle] +pub extern fn test_Big(_: Big) -> Big { loop {} } + +// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [16 x i32] +#[no_mangle] +pub extern fn test_BigW(_: BigW) -> BigW { loop {} } + + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct BigUw(BigU); + +// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [16 x i32] +#[no_mangle] +pub extern fn test_BigU(_: BigU) -> BigU { loop {} } + +// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [16 x i32] +#[no_mangle] +pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs new file mode 100644 index 00000000000..31020d8b94f --- /dev/null +++ b/src/test/codegen/repr-transparent.rs @@ -0,0 +1,177 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type="lib"] +#![feature(repr_transparent, repr_simd)] + +use std::marker::PhantomData; + +pub struct Zst1; +pub struct Zst2(()); + +#[repr(transparent)] +pub struct F32(f32); + +// CHECK: define float @test_F32(float %arg0) +#[no_mangle] +pub extern fn test_F32(_: F32) -> F32 { loop {} } + +#[repr(transparent)] +pub struct Ptr(*mut u8); + +// CHECK: define i8* @test_Ptr(i8* %arg0) +#[no_mangle] +pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} } + +#[repr(transparent)] +pub struct WithZst(u64, Zst1); + +// CHECK: define i64 @test_WithZst(i64 %arg0) +#[no_mangle] +pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} } + +#[repr(transparent)] +pub struct WithZeroSizedArray(*const f32, [i8; 0]); + +// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. +// CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0) +#[no_mangle] +pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } + +#[repr(transparent)] +pub struct Generic(T); + +// CHECK: define double @test_Generic(double %arg0) +#[no_mangle] +pub extern fn test_Generic(_: Generic) -> Generic { loop {} } + +#[repr(transparent)] +pub struct GenericPlusZst(T, Zst2); + +#[repr(u8)] +pub enum Bool { True, False, FileNotFound } + +// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0) +#[no_mangle] +pub extern fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { loop {} } + +#[repr(transparent)] +pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); + +// CHECK: define i16* @test_LifetimePhantom(i16* %arg0) +#[no_mangle] +pub extern fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { loop {} } + +// This works despite current alignment resrictions because PhantomData is always align(1) +#[repr(transparent)] +pub struct UnitPhantom { val: T, unit: PhantomData } + +pub struct Px; + +// CHECK: define float @test_UnitPhantom(float %arg0) +#[no_mangle] +pub extern fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { loop {} } + +#[repr(transparent)] +pub struct TwoZsts(Zst1, i8, Zst2); + +// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0) +#[no_mangle] +pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} } + +#[repr(transparent)] +pub struct Nested1(Zst2, Generic); + +// CHECK: define double @test_Nested1(double %arg0) +#[no_mangle] +pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} } + +#[repr(transparent)] +pub struct Nested2(Nested1, Zst1); + +// CHECK: define double @test_Nested2(double %arg0) +#[no_mangle] +pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} } + +#[repr(simd)] +struct f32x4(f32, f32, f32, f32); + +#[repr(transparent)] +pub struct Vector(f32x4); + +// CHECK: define <4 x float> @test_Vector(<4 x float> %arg0) +#[no_mangle] +pub extern fn test_Vector(_: Vector) -> Vector { loop {} } + +trait Mirror { type It: ?Sized; } +impl Mirror for T { type It = Self; } + +#[repr(transparent)] +pub struct StructWithProjection(::It); + +// CHECK: define float @test_Projection(float %arg0) +#[no_mangle] +pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } + + +// The rest of this file tests newtypes around small aggregates on an ABI where small aggregates are +// packed into one register. This is ABI-dependent, so instead we focus on one ABI and supply a +// dummy definition for other ABIs to keep FileCheck happy. +// +// Bigger aggregates are tested in separate files called repr-transparent-aggregate-*.rs because +// there, the expected LLVM IR function signatures vary so much that it's not reasonably possible to +// cover all of them with a single CHECK line. Instead we group ABIs by the general "shape" of the +// signature and have a separate test file for each bin. +// +// PS: You may be wondering why we don't just compare the return types and argument types for +// equality with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on +// newtypes containing aggregates. This is OK on all ABIs we support, but because LLVM has not +// gotten rid of pointee types yet, the IR function signature will be syntactically different (%Foo* +// vs %FooWrapper*). + +#[repr(C)] +pub struct Rgb8 { r: u8, g: u8, b: u8 } + +#[repr(transparent)] +pub struct Rgb8Wrap(Rgb8); + +// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not +// CHECK: define i32 @test_Rgb8Wrap(i32 +#[no_mangle] +#[cfg(all(target_arch="x86_64", target_os="linux"))] +pub extern fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} } + +#[cfg(not(all(target_arch="x86_64", target_os="linux")))] +#[no_mangle] +pub extern fn test_Rgb8Wrap(_: u32) -> u32 { loop {} } + +// Same as with the small struct above: ABI-dependent, we only test the interesting case +// (ABIs that pack the aggregate into a scalar) and stub it out on other ABIs + +#[repr(C)] +pub union FloatBits { + float: f32, + bits: u32, +} + +#[repr(transparent)] +pub struct SmallUnion(FloatBits); + +// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not +// CHECK: define i32 @test_SmallUnion(i32 +#[no_mangle] +#[cfg(all(target_arch="x86_64", target_os="linux"))] +pub extern fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} } + +#[cfg(not(all(target_arch="x86_64", target_os="linux")))] +#[no_mangle] +pub extern fn test_SmallUnion(_: u32) -> u32 { loop {} } -- cgit 1.4.1-3-g733a5 From 9eb473579a19f456e53920dd6e6f8e75eb08dc62 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Fri, 12 Jan 2018 23:32:14 +0100 Subject: Compute LLVM argument indices correctly in face of padding Closes #47278 --- src/librustc_trans/abi.rs | 3 --- src/librustc_trans/mir/mod.rs | 3 +++ src/test/codegen/issue-47278.rs | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/issue-47278.rs (limited to 'src/test/codegen') diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 07f9b8fed8b..5079ce77523 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -608,9 +608,6 @@ impl<'a, 'tcx> ArgType<'tcx> { } pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { - if self.pad.is_some() { - *idx += 1; - } let mut next = || { let val = llvm::get_param(bx.llfn(), *idx as c_uint); *idx += 1; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index ddd78f268fa..3064e2f7c7a 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -402,6 +402,9 @@ fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_ty.args[idx]; idx += 1; + if arg.pad.is_some() { + llarg_idx += 1; + } arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i)); } diff --git a/src/test/codegen/issue-47278.rs b/src/test/codegen/issue-47278.rs new file mode 100644 index 00000000000..21858b434bf --- /dev/null +++ b/src/test/codegen/issue-47278.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// -C no-prepopulate-passes +#![crate_type="staticlib"] + +#[repr(C)] +pub struct Foo(u64); + +// CHECK: define {{.*}} @foo( +#[no_mangle] +pub extern fn foo(_: Foo) -> Foo { loop {} } -- cgit 1.4.1-3-g733a5 From 7188706c4fbbae660fa7eb6f2bf13130ddf1726a Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sat, 20 Jan 2018 14:32:33 -0600 Subject: Teach rustc about DW_AT_noreturn and a few more DIFlags --- src/librustc_llvm/ffi.rs | 4 ++++ src/librustc_trans/debuginfo/mod.rs | 3 +++ src/rustllvm/RustWrapper.cpp | 20 ++++++++++++++++++-- src/test/codegen/noreturnflag.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/test/codegen/noreturnflag.rs (limited to 'src/test/codegen') diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b97e37f4c8f..8602c559da9 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -498,6 +498,10 @@ pub mod debuginfo { const FlagStaticMember = (1 << 12); const FlagLValueReference = (1 << 13); const FlagRValueReference = (1 << 14); + const FlagExternalTypeRef = (1 << 15); + const FlagIntroducedVirtual = (1 << 18); + const FlagBitField = (1 << 19); + const FlagNoReturn = (1 << 20); const FlagMainSubprogram = (1 << 21); } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index b46e12d9d5b..9071eb776d5 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -270,6 +270,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } None => {} }; + if sig.output().is_never() { + flags = flags | DIFlags::FlagNoReturn; + } let fn_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFunction( diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 95130d596e1..2e8207d1cbb 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -457,9 +457,13 @@ enum class LLVMRustDIFlags : uint32_t { FlagStaticMember = (1 << 12), FlagLValueReference = (1 << 13), FlagRValueReference = (1 << 14), - FlagMainSubprogram = (1 << 21), + FlagExternalTypeRef = (1 << 15), + FlagIntroducedVirtual = (1 << 18), + FlagBitField = (1 << 19), + FlagNoReturn = (1 << 20), + FlagMainSubprogram = (1 << 21), // Do not add values that are not supported by the minimum LLVM - // version we support! + // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def }; inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) { @@ -545,6 +549,18 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { Result |= DINode::DIFlags::FlagRValueReference; } #if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) + if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) { + Result |= DINode::DIFlags::FlagExternalTypeRef; + } + if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { + Result |= DINode::DIFlags::FlagIntroducedVirtual; + } + if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { + Result |= DINode::DIFlags::FlagBitField; + } + if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { + Result |= DINode::DIFlags::FlagNoReturn; + } if (isSet(Flags & LLVMRustDIFlags::FlagMainSubprogram)) { Result |= DINode::DIFlags::FlagMainSubprogram; } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs new file mode 100644 index 00000000000..473fed8e046 --- /dev/null +++ b/src/test/codegen/noreturnflag.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// min-llvm-version 3.8 + +// compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: foo +// CHECK: {{.*}}DISubprogram{{.*}} name: "foo",{{.*}}DIFlagNoReturn{{.*}} + +#[no_mangle] +pub fn foo() -> ! { + loop {} +} + +// CHECK-LABEL: main +// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} + +pub fn main() { + foo(); +} -- cgit 1.4.1-3-g733a5 From f7f6598083f24191bbdb170b993dbf97abd1b5c9 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sat, 20 Jan 2018 21:22:11 -0600 Subject: Simplify and fix test --- src/test/codegen/noreturnflag.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 473fed8e046..3fa7921b444 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -13,15 +13,12 @@ // compile-flags: -g -C no-prepopulate-passes -// CHECK-LABEL: foo -// CHECK: {{.*}}DISubprogram{{.*}} name: "foo",{{.*}}DIFlagNoReturn{{.*}} +// CHECK: {{.*}}DISubprogram{{.*}}name: "foo"{{.*}}DIFlagNoReturn -#[no_mangle] -pub fn foo() -> ! { +fn foo() -> ! { loop {} } -// CHECK-LABEL: main // CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} pub fn main() { -- cgit 1.4.1-3-g733a5 From e0f9b26899ea16bb2b6b966266e46698ebad9c4a Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sun, 21 Jan 2018 12:36:25 -0600 Subject: Ensure test doesn't run with llvm 3.9 --- src/rustllvm/RustWrapper.cpp | 2 +- src/test/codegen/noreturnflag.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/test/codegen') diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 2e8207d1cbb..42ddf5663f9 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -548,7 +548,6 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { Result |= DINode::DIFlags::FlagRValueReference; } -#if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) { Result |= DINode::DIFlags::FlagExternalTypeRef; } @@ -558,6 +557,7 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { Result |= DINode::DIFlags::FlagBitField; } +#if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { Result |= DINode::DIFlags::FlagNoReturn; } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 3fa7921b444..24a5a4e44cb 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// min-llvm-version 3.8 +// min-llvm-version 4.0 // compile-flags: -g -C no-prepopulate-passes @@ -19,8 +19,6 @@ fn foo() -> ! { loop {} } -// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} - pub fn main() { foo(); } -- cgit 1.4.1-3-g733a5 From 651ea8ea44d8ac8a02dc357412eb73f830057cae Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Tue, 26 Dec 2017 10:24:23 +1100 Subject: Stabilized `#[repr(align(x))]` attribute (RFC 1358) --- src/liballoc/tests/lib.rs | 1 - src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 30 ++++++++++++---------- src/test/codegen/align-struct.rs | 3 --- src/test/compile-fail/conflicting-repr-hints.rs | 2 -- src/test/compile-fail/repr-align.rs | 2 -- .../compile-fail/repr-packed-contains-align.rs | 2 -- src/test/run-pass/align-struct.rs | 2 -- src/test/run-pass/union/union-align.rs | 2 -- src/test/ui/feature-gate-repr_align.rs | 15 ----------- src/test/ui/feature-gate-repr_align.stderr | 10 -------- src/test/ui/print_type_sizes/repr-align.rs | 2 -- src/test/ui/span/gated-features-attr-spans.rs | 2 +- src/test/ui/span/gated-features-attr-spans.stderr | 10 +------- 14 files changed, 20 insertions(+), 65 deletions(-) delete mode 100644 src/test/ui/feature-gate-repr_align.rs delete mode 100644 src/test/ui/feature-gate-repr_align.stderr (limited to 'src/test/codegen') diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index eee229bc6fd..427a7adcbde 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(repr_align)] #![feature(slice_rotate)] #![feature(splice)] #![feature(str_escape)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 91cc6d25cce..a8049e676b3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -296,7 +296,6 @@ #![feature(ptr_internals)] #![feature(rand)] #![feature(raw)] -#![feature(repr_align)] #![feature(rustc_attrs)] #![feature(sip_hash_13)] #![feature(slice_bytes)] @@ -323,6 +322,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![cfg_attr(stage0, feature(repr_align))] #![default_lib_allocator] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ac5a10ec703..5a7b53153fd 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -343,9 +343,6 @@ declare_features! ( // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), - // Allows `repr(align(u16))` struct attribute (RFC 1358) - (active, repr_align, "1.17.0", Some(33626)), - // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289)), @@ -546,6 +543,8 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), + // Allows `repr(align(16))` struct attribute (RFC 1358) + (accepted, repr_align, "1.24.0", Some(33626)), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1456,15 +1455,25 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + // allow attr_literals in #[repr(align(x))] + let mut is_repr_align = false; + if attr.path == "repr" { + if let Some(content) = attr.meta_item_list() { + is_repr_align = content.iter().any(|c| c.check_name("align")); + } + } + if self.context.features.proc_macro && attr::is_known(attr) { return } - let meta = panictry!(attr.parse_meta(self.context.parse_sess)); - if contains_novel_literal(&meta) { - gate_feature_post!(&self, attr_literals, attr.span, - "non-string literals in attributes, or string \ - literals in top-level positions, are experimental"); + if !is_repr_align { + let meta = panictry!(attr.parse_meta(self.context.parse_sess)); + if contains_novel_literal(&meta) { + gate_feature_post!(&self, attr_literals, attr.span, + "non-string literals in attributes, or string \ + literals in top-level positions, are experimental"); + } } } @@ -1522,11 +1531,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } - if item.check_name("align") { - gate_feature_post!(&self, repr_align, attr.span, - "the struct `#[repr(align(u16))]` attribute \ - is experimental"); - } if item.check_name("transparent") { gate_feature_post!(&self, repr_transparent, attr.span, "the `#[repr(transparent)]` attribute \ diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index ab9f5dda3a1..155319cb154 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -13,9 +13,6 @@ #![crate_type = "lib"] -#![feature(attr_literals)] -#![feature(repr_align)] - #[repr(align(64))] pub struct Align64(i32); // CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 12ac8fb57b1..8acc8b7bb1e 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -9,8 +9,6 @@ // except according to those terms. #![allow(dead_code)] -#![feature(attr_literals)] -#![feature(repr_align)] #[repr(C)] enum A { A } diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index bc9cf065e5a..7c8eb6a2de9 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] -#![feature(attr_literals)] -#![feature(repr_align)] #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer struct A(i32); diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs index 78d43064ea3..27890333a51 100644 --- a/src/test/compile-fail/repr-packed-contains-align.rs +++ b/src/test/compile-fail/repr-packed-contains-align.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(untagged_unions)] #![allow(dead_code)] diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index e42aa868c47..dea8462705f 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(box_syntax)] use std::mem; diff --git a/src/test/run-pass/union/union-align.rs b/src/test/run-pass/union/union-align.rs index c0100df53e7..54e4e12d24f 100644 --- a/src/test/run-pass/union/union-align.rs +++ b/src/test/run-pass/union/union-align.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(untagged_unions)] use std::mem::{size_of, size_of_val, align_of, align_of_val}; diff --git a/src/test/ui/feature-gate-repr_align.rs b/src/test/ui/feature-gate-repr_align.rs deleted file mode 100644 index 9591d367a2d..00000000000 --- a/src/test/ui/feature-gate-repr_align.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![feature(attr_literals)] - -#[repr(align(64))] //~ error: the struct `#[repr(align(u16))]` attribute is experimental -struct Foo(u64, u64); - -fn main() {} diff --git a/src/test/ui/feature-gate-repr_align.stderr b/src/test/ui/feature-gate-repr_align.stderr deleted file mode 100644 index dd88067d58f..00000000000 --- a/src/test/ui/feature-gate-repr_align.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0658]: the struct `#[repr(align(u16))]` attribute is experimental (see issue #33626) - --> $DIR/feature-gate-repr_align.rs:12:1 - | -12 | #[repr(align(64))] //~ error: the struct `#[repr(align(u16))]` attribute is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_align)] to the crate attributes to enable - -error: aborting due to previous error - diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs index 108b8dbba01..92928bba1c3 100644 --- a/src/test/ui/print_type_sizes/repr-align.rs +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -18,8 +18,6 @@ // It avoids using u64/i64 because on some targets that is only 4-byte // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(start)] #![allow(dead_code)] diff --git a/src/test/ui/span/gated-features-attr-spans.rs b/src/test/ui/span/gated-features-attr-spans.rs index ace185d0169..83a4c5d5dd2 100644 --- a/src/test/ui/span/gated-features-attr-spans.rs +++ b/src/test/ui/span/gated-features-attr-spans.rs @@ -10,7 +10,7 @@ #![feature(attr_literals)] -#[repr(align(16))] //~ ERROR is experimental +#[repr(align(16))] struct Gem { mohs_hardness: u8, poofed: bool, diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 74a2c1d742b..f15c4a72c5a 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,11 +1,3 @@ -error[E0658]: the struct `#[repr(align(u16))]` attribute is experimental (see issue #33626) - --> $DIR/gated-features-attr-spans.rs:13:1 - | -13 | #[repr(align(16))] //~ ERROR is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_align)] to the crate attributes to enable - error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) --> $DIR/gated-features-attr-spans.rs:20:1 | @@ -30,5 +22,5 @@ warning: `#[must_use]` on functions is experimental (see issue #43302) | = help: add #![feature(fn_must_use)] to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 502de01ff40d37d3e6b419c3931a23284ce1a4e4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 08:00:22 -0800 Subject: rustc: SIMD types use pointers in Rust's ABI This commit changes the ABI of SIMD types in the "Rust" ABI to unconditionally be passed via pointers instead of being passed as immediates. This should fix a longstanding issue, #44367, where SIMD-using programs ended up showing very odd behavior at runtime because the ABI between functions was mismatched. As a bit of a recap, this is sort of an LLVM bug and sort of an LLVM feature (today's behavior). LLVM will generate code for a function solely looking at the function it's generating, including calls to other functions. Let's then say you've got something that looks like: ```llvm define void @foo() { ; no target features enabled call void @bar( zeroinitializer) ret void } define void @bar() #0 { ; enables the AVX feature ... } ``` LLVM will codegen the call to `bar` *without* using AVX registers becauase `foo` doesn't have access to these registers. Instead it's generated with emulation that uses two 128-bit registers. The `bar` function, on the other hand, will expect its argument in an AVX register (as it has AVX enabled). This means we've got a codegen problem! Comments on #44367 have some more contexutal information but the crux of the issue is that if we want SIMD to work in general we'll need to ensure that whenever a function calls another they ABI of the arguments being passed is in agreement. One possible solution to this would be to insert "shim functions" where whenever a `target_feature` mismatch is detected the compiler inserts a shim function where you pass arguments via memory to the shim and then the shim loads the values and calls the target function (where the shim and the target have the same target features enabled). This unfortunately is quite nontrivial to implement in rustc today (especially when accounting for function pointers and such). This commit takes a different solution, *always* passing SIMD arguments through memory instead of passing as immediates. This strategy solves the problem at the LLVM layer because the ABI between two functions never uses SIMD registers. This also shouldn't be a hit to performance because SIMD performance is thought to often rely on inlining anyway, where a `call` instruction, even if using SIMD registers, would be disastrous to performance regardless. LLVM should then be more than capable of fixing all our memory usage to use registers instead after enough inlining has been performed. Note that there's a few caveats to this commit though: * The "platform intrinsic" ABI is omitted from "always pass via memory". This ABI is used to define intrinsics like `simd_shuffle4` where LLVM and rustc need to have the arguments as an immediate. * Additionally this commit does *not* fix the `extern` ("C") ABI. This means that the bug in #44367 can still happen when using non-Rust-ABI functions. My hope is that before stabilization we can ban and/or warn about SIMD types in these functions (as AFAIK there's not much motivation to belong there anyway), but I'll leave that for a later commit and if this is merged I'll file a follow-up issue. All in all this... Closes #44367 --- src/librustc_trans/abi.rs | 25 ++++ src/test/codegen/x86_mmx.rs | 4 +- src/test/run-pass/simd-target-feature-mixup.rs | 181 +++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/simd-target-feature-mixup.rs (limited to 'src/test/codegen') diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 5079ce77523..9cabd9356e9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -871,6 +871,31 @@ impl<'a, 'tcx> FnType<'tcx> { match arg.layout.abi { layout::Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the platform intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => { + arg.make_indirect(); + return + } + _ => return } diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index bedda63bbff..dc9f63c35db 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -22,9 +22,7 @@ pub struct i8x8(u64); #[no_mangle] pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 { - // CHECK-LABEL: define x86_mmx @a(x86_mmx*{{.*}}, x86_mmx{{.*}}) - // CHECK: store x86_mmx %b, x86_mmx* %a - // CHECK: ret x86_mmx %b + // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}}) *a = b; return b } diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs new file mode 100644 index 00000000000..b60aec2b5c9 --- /dev/null +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -0,0 +1,181 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, target_feature, cfg_target_feature)] + +use std::process::{Command, ExitStatus}; +use std::env; + +fn main() { + if let Some(level) = env::args().nth(1) { + return test::main(&level) + } + + let me = env::current_exe().unwrap(); + for level in ["sse", "avx", "avx512"].iter() { + let status = Command::new(&me).arg(level).status().unwrap(); + if status.success() { + println!("success with {}", level); + continue + } + + // We don't actually know if our computer has the requisite target features + // for the test below. Testing for that will get added to libstd later so + // for now just asume sigill means this is a machine that can't run this test. + if is_sigill(status) { + println!("sigill with {}, assuming spurious", level); + continue + } + panic!("invalid status at {}: {}", level, status); + } +} + +#[cfg(unix)] +fn is_sigill(status: ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(4) +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(bad_style)] +mod test { + // An SSE type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m128i(u64, u64); + + // An AVX type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m256i(u64, u64, u64, u64); + + // An AVX-512 type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); + + pub fn main(level: &str) { + unsafe { + main_normal(level); + main_sse(level); + if level == "sse" { + return + } + main_avx(level); + if level == "avx" { + return + } + main_avx512(level); + } + } + + macro_rules! mains { + ($( + $(#[$attr:meta])* + unsafe fn $main:ident(level: &str) { + ... + } + )*) => ($( + $(#[$attr])* + unsafe fn $main(level: &str) { + let m128 = __m128i(1, 2); + let m256 = __m256i(3, 4, 5, 6); + let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); + assert_eq!(id_sse_128(m128), m128); + assert_eq!(id_sse_256(m256), m256); + assert_eq!(id_sse_512(m512), m512); + + if level == "sse" { + return + } + assert_eq!(id_avx_128(m128), m128); + assert_eq!(id_avx_256(m256), m256); + assert_eq!(id_avx_512(m512), m512); + + if level == "avx" { + return + } + assert_eq!(id_avx512_128(m128), m128); + assert_eq!(id_avx512_256(m256), m256); + assert_eq!(id_avx512_512(m512), m512); + } + )*) + } + + mains! { + unsafe fn main_normal(level: &str) { ... } + #[target_feature(enable = "sse2")] + unsafe fn main_sse(level: &str) { ... } + #[target_feature(enable = "avx")] + unsafe fn main_avx(level: &str) { ... } + #[target_feature(enable = "avx512bw")] + unsafe fn main_avx512(level: &str) { ... } + } + + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +mod test { + pub fn main(level: &str) {} +} -- cgit 1.4.1-3-g733a5 From 973756d715f9caaeee44e9387f5c60458ae5c4fc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 31 Jan 2018 00:23:25 +0200 Subject: rustc_trans: keep LLVM types for trait objects anonymous. --- src/librustc_trans/type_of.rs | 4 +++- src/test/codegen/function-arguments.rs | 4 ++-- src/test/run-pass/issue-47638.rs | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-47638.rs (limited to 'src/test/codegen') diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b1533cfad19..af957500f70 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -57,7 +57,9 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyAdt(..) | - ty::TyDynamic(..) | + // FIXME(eddyb) producing readable type names for trait objects can result + // in problematically distinct types due to HRTB and subtyping (see #47638). + // ty::TyDynamic(..) | ty::TyForeign(..) | ty::TyStr => { let mut name = String::with_capacity(32); diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index f8945a6ee8d..0e98d3f9050 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -122,13 +122,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { pub fn str(_: &[u8]) { } -// CHECK: @trait_borrow(%"core::ops::drop::Drop"* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1) +// CHECK: @trait_borrow({}* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box(%"core::ops::drop::Drop"* noalias nonnull, {}* noalias nonnull readonly) +// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) #[no_mangle] pub fn trait_box(_: Box) { } diff --git a/src/test/run-pass/issue-47638.rs b/src/test/run-pass/issue-47638.rs new file mode 100644 index 00000000000..6f627b2a3c1 --- /dev/null +++ b/src/test/run-pass/issue-47638.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn id<'c, 'b>(f: &'c &'b Fn(&i32)) -> &'c &'b Fn(&'static i32) { + f +} + +fn main() { + let f: &Fn(&i32) = &|x| {}; + id(&f); +} -- cgit 1.4.1-3-g733a5 From e2de8deb0927eb68dbc5986e1fbbd0a1359f8a74 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 30 Jan 2018 16:47:30 -0800 Subject: Enable stack-probe tests with system LLVM >= 5.0 --- src/test/codegen/stack-probes.rs | 2 +- src/test/run-pass/stack-probes-lto.rs | 2 +- src/test/run-pass/stack-probes.rs | 2 +- src/tools/compiletest/src/header.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 5b26dade9af..4a489f1edb3 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -15,7 +15,7 @@ // ignore-wasm // ignore-emscripten // ignore-windows -// no-system-llvm +// min-system-llvm-version 5.0 // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index 22555c8d6a7..4deced1297b 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -15,7 +15,7 @@ // ignore-emscripten no processes // ignore-musl FIXME #31506 // ignore-pretty -// no-system-llvm +// min-system-llvm-version 5.0 // compile-flags: -C lto // no-prefer-dynamic diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index 248ad701926..4224a65ffd7 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -14,7 +14,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-musl FIXME #31506 -// no-system-llvm +// min-system-llvm-version 5.0 use std::mem; use std::process::Command; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ff662736bdd..80750f9a3fe 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -167,7 +167,7 @@ impl EarlyProps { .expect("Malformed llvm version directive"); // Ignore if using system LLVM and actual version // is smaller the minimum required version - !(config.system_llvm && &actual_version[..] < min_version) + config.system_llvm && &actual_version[..] < min_version } else { false } -- cgit 1.4.1-3-g733a5 From 75474ff1323c2968bb2dafc8b8f0af4817a89d01 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 2 Feb 2018 09:31:56 +0100 Subject: TrustedLen for Repeat / RangeFrom test cases --- src/libcore/tests/iter.rs | 43 ++++++++++++++++++++++++++++++++++ src/test/codegen/repeat-trusted-len.rs | 23 ++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/test/codegen/repeat-trusted-len.rs (limited to 'src/test/codegen') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index e52e119ff59..f6b12fbb2dd 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1371,6 +1371,29 @@ fn test_range_from_nth() { assert_eq!(r, 16..); assert_eq!(r.nth(10), Some(26)); assert_eq!(r, 27..); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); +} + +fn is_trusted_len(_: I) {} + +#[test] +fn test_range_from_take() { + let mut it = (0..).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + is_trusted_len((0..).take(3)); + assert_eq!((0..).take(3).size_hint(), (3, Some(3))); + assert_eq!((0..).take(0).size_hint(), (0, Some(0))); + assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_range_from_take_collect() { + let v: Vec<_> = (0..).take(3).collect(); + assert_eq!(v, vec![0, 1, 2]); } #[test] @@ -1465,6 +1488,26 @@ fn test_repeat() { assert_eq!(it.next(), Some(42)); assert_eq!(it.next(), Some(42)); assert_eq!(it.next(), Some(42)); + assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_take() { + let mut it = repeat(42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat(42).take(3)); + assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let v: Vec<_> = repeat(42).take(3).collect(); + assert_eq!(v, vec![42, 42, 42]); } #[test] diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs new file mode 100644 index 00000000000..43872f15d51 --- /dev/null +++ b/src/test/codegen/repeat-trusted-len.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O +// ignore-tidy-linelength + +#![crate_type = "lib"] + +use std::iter; + +// CHECK-LABEL: @repeat_take_collect +#[no_mangle] +pub fn repeat_take_collect() -> Vec { +// CHECK: call void @llvm.memset.p0i8 + iter::repeat(42).take(100000).collect() +} -- cgit 1.4.1-3-g733a5 From a29d8545b573d008e364571a83fcd865748a8ad8 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 16 Nov 2017 10:08:19 +0100 Subject: Make inline assembly volatile if it has no outputs. Fixes #46026 --- src/libsyntax_ext/asm.rs | 6 ++++++ src/test/codegen/no-output-asm-is-volatile.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/codegen/no-output-asm-is-volatile.rs (limited to 'src/test/codegen') diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 3742fb8c804..d1de4dccd00 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -239,6 +239,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } } + // If there are no outputs, the inline assembly is executed just for its side effects, + // so ensure that it is volatile + if outputs.is_empty() { + volatile = true; + } + MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { diff --git a/src/test/codegen/no-output-asm-is-volatile.rs b/src/test/codegen/no-output-asm-is-volatile.rs new file mode 100644 index 00000000000..457d706a8ff --- /dev/null +++ b/src/test/codegen/no-output-asm-is-volatile.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +// ignore-asmjs + +#![feature(asm)] +#![crate_type = "lib"] + +// Check that inline assembly expressions without any outputs +// are marked as having side effects / being volatile + +// CHECK-LABEL: @assembly +#[no_mangle] +pub fn assembly() { + unsafe { asm!("") } +// CHECK: tail call void asm sideeffect "", {{.*}} +} -- cgit 1.4.1-3-g733a5 From 5f3dc8b7b2b8fb4837adfe5defa92367f8fe1000 Mon Sep 17 00:00:00 2001 From: Björn Steinbrink Date: Sat, 20 Jan 2018 17:09:55 +0100 Subject: Fix oversized loads on x86_64 SysV FFI calls The x86_64 SysV ABI should use exact sizes for small structs passed in registers, i.e. a struct that occupies 3 bytes should use an i24, instead of the i32 it currently uses. Refs #45543 --- src/librustc_trans/cabi_x86_64.rs | 13 ++++--- src/test/codegen/abi-x86_64_sysv.rs | 39 +++++++++++++++++++ src/test/codegen/repr-transparent-sysv64.rs | 39 +++++++++++++++++++ src/test/codegen/repr-transparent.rs | 60 +++++------------------------ 4 files changed, 94 insertions(+), 57 deletions(-) create mode 100644 src/test/codegen/abi-x86_64_sysv.rs create mode 100644 src/test/codegen/repr-transparent-sysv64.rs (limited to 'src/test/codegen') diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 62bac8469ce..b8144a3ca7a 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -134,12 +134,13 @@ fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option None, Some(Class::Int) => { *i += 1; - Some(match size.bytes() { - 1 => Reg::i8(), - 2 => Reg::i16(), - 3 | - 4 => Reg::i32(), - _ => Reg::i64() + Some(if size.bytes() < 8 { + Reg { + kind: RegKind::Integer, + size + } + } else { + Reg::i64() }) } Some(Class::Sse) => { diff --git a/src/test/codegen/abi-x86_64_sysv.rs b/src/test/codegen/abi-x86_64_sysv.rs new file mode 100644 index 00000000000..88666e9c1fd --- /dev/null +++ b/src/test/codegen/abi-x86_64_sysv.rs @@ -0,0 +1,39 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +pub struct S24 { + a: i8, + b: i8, + c: i8, +} + +pub struct S48 { + a: i16, + b: i16, + c: i8, +} + +// CHECK: i24 @struct_24_bits(i24 +#[no_mangle] +pub extern "sysv64" fn struct_24_bits(a: S24) -> S24 { + a +} + +// CHECK: i48 @struct_48_bits(i48 +#[no_mangle] +pub extern "sysv64" fn struct_48_bits(a: S48) -> S48 { + a +} diff --git a/src/test/codegen/repr-transparent-sysv64.rs b/src/test/codegen/repr-transparent-sysv64.rs new file mode 100644 index 00000000000..7a30983fdd3 --- /dev/null +++ b/src/test/codegen/repr-transparent-sysv64.rs @@ -0,0 +1,39 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 + +// compile-flags: -C no-prepopulate-passes + +#![crate_type="lib"] +#![feature(repr_transparent)] + +#[repr(C)] +pub struct Rgb8 { r: u8, g: u8, b: u8 } + +#[repr(transparent)] +pub struct Rgb8Wrap(Rgb8); + +// CHECK: i24 @test_Rgb8Wrap(i24) +#[no_mangle] +pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} } + +#[repr(C)] +pub union FloatBits { + float: f32, + bits: u32, +} + +#[repr(transparent)] +pub struct SmallUnion(FloatBits); + +// CHECK: i32 @test_SmallUnion(i32) +#[no_mangle] +pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index 31020d8b94f..087fa9b16b4 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -123,55 +123,13 @@ pub struct StructWithProjection(::It); pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } -// The rest of this file tests newtypes around small aggregates on an ABI where small aggregates are -// packed into one register. This is ABI-dependent, so instead we focus on one ABI and supply a -// dummy definition for other ABIs to keep FileCheck happy. +// All that remains to be tested are aggregates. They are tested in separate files called repr- +// transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR +// function signatures vary so much that it's not reasonably possible to cover all of them with a +// single CHECK line. // -// Bigger aggregates are tested in separate files called repr-transparent-aggregate-*.rs because -// there, the expected LLVM IR function signatures vary so much that it's not reasonably possible to -// cover all of them with a single CHECK line. Instead we group ABIs by the general "shape" of the -// signature and have a separate test file for each bin. -// -// PS: You may be wondering why we don't just compare the return types and argument types for -// equality with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on -// newtypes containing aggregates. This is OK on all ABIs we support, but because LLVM has not -// gotten rid of pointee types yet, the IR function signature will be syntactically different (%Foo* -// vs %FooWrapper*). - -#[repr(C)] -pub struct Rgb8 { r: u8, g: u8, b: u8 } - -#[repr(transparent)] -pub struct Rgb8Wrap(Rgb8); - -// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not -// CHECK: define i32 @test_Rgb8Wrap(i32 -#[no_mangle] -#[cfg(all(target_arch="x86_64", target_os="linux"))] -pub extern fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} } - -#[cfg(not(all(target_arch="x86_64", target_os="linux")))] -#[no_mangle] -pub extern fn test_Rgb8Wrap(_: u32) -> u32 { loop {} } - -// Same as with the small struct above: ABI-dependent, we only test the interesting case -// (ABIs that pack the aggregate into a scalar) and stub it out on other ABIs - -#[repr(C)] -pub union FloatBits { - float: f32, - bits: u32, -} - -#[repr(transparent)] -pub struct SmallUnion(FloatBits); - -// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not -// CHECK: define i32 @test_SmallUnion(i32 -#[no_mangle] -#[cfg(all(target_arch="x86_64", target_os="linux"))] -pub extern fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} } - -#[cfg(not(all(target_arch="x86_64", target_os="linux")))] -#[no_mangle] -pub extern fn test_SmallUnion(_: u32) -> u32 { loop {} } +// You may be wondering why we don't just compare the return types and argument types for equality +// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes +// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of +// pointee types yet, the IR function signature will be syntactically different (%Foo* vs +// %FooWrapper*). -- cgit 1.4.1-3-g733a5 From 6e5dacbd5e8aab43cdc4c2f1d4ec66fe0b8d4bed Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 7 Feb 2018 17:28:32 +0200 Subject: rustc_mir: always run the deaggregator. --- src/librustc_mir/transform/deaggregator.rs | 5 ----- src/librustc_mir/transform/mod.rs | 6 +++++- src/test/codegen/lifetime_start_end.rs | 8 ++++---- src/test/codegen/match.rs | 6 +++--- src/test/incremental/hashes/closure_expressions.rs | 2 +- src/test/incremental/issue-38222.rs | 2 +- src/test/ui/print_type_sizes/generics.rs | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 179c196f26f..44c35960aba 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -39,11 +39,6 @@ impl MirPass for Deaggregator { } } - // We only run when the MIR optimization level is > 2. - if tcx.sess.opts.debugging_opts.mir_opt_level <= 2 { - return; - } - let can_deaggregate = |statement: &Statement| { if let StatementKind::Assign(_, ref rhs) = statement.kind { if let Rvalue::Aggregate(..) = *rhs { diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7ed250e94c5..b16c1436a1c 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -258,6 +258,11 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx // Optimizations begin. inline::Inline, + + // Lowering generator control-flow and variables + // has to happen before we do anything else to them. + generator::StateTransform, + instcombine::InstCombine, deaggregator::Deaggregator, copy_prop::CopyPropagation, @@ -265,7 +270,6 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx simplify::SimplifyCfg::new("final"), simplify::SimplifyLocals, - generator::StateTransform, add_call_guards::CriticalCallEdges, dump_mir::Marker("PreTrans"), ]; diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 1f900a3770e..62aa93398ac 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -28,14 +28,14 @@ pub fn test() { // CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* -// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__5]]) +// CHECK: [[S__4:%[0-9]+]] = bitcast %"core::option::Option"* %_4 to i8* +// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]]) // CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) -// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* -// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__5]]) +// CHECK: [[E__4:%[0-9]+]] = bitcast %"core::option::Option"* %_4 to i8* +// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]]) } let c = 1; diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs index 660b6346c57..c9d0427dd0a 100644 --- a/src/test/codegen/match.rs +++ b/src/test/codegen/match.rs @@ -19,7 +19,7 @@ pub enum E { // CHECK-LABEL: @exhaustive_match #[no_mangle] -pub fn exhaustive_match(e: E) { +pub fn exhaustive_match(e: E, unit: ()) { // CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [ // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]] // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]] @@ -31,7 +31,7 @@ pub fn exhaustive_match(e: E) { // CHECK: [[OTHERWISE]]: // CHECK-NEXT: unreachable match e { - E::A => (), - E::B => (), + E::A => unit, + E::B => unit, } } diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index d8a87da5918..73418f48860 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -64,7 +64,7 @@ pub fn change_parameter_pattern() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, MirOptimized, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_pattern() { let _ = |&x: &u32| x; diff --git a/src/test/incremental/issue-38222.rs b/src/test/incremental/issue-38222.rs index 7bb8af74eeb..f890672aa8f 100644 --- a/src/test/incremental/issue-38222.rs +++ b/src/test/incremental/issue-38222.rs @@ -18,7 +18,7 @@ #![feature(rustc_attrs)] -#![rustc_partition_translated(module="issue_38222-mod1", cfg="rpass2")] +#![rustc_partition_reused(module="issue_38222-mod1", cfg="rpass2")] // If trans had added a dependency edge to the Krate dep-node, nothing would // be re-used, so checking that this module was re-used is sufficient. diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs index d0e5bd1d92a..21fdbb3f5a1 100644 --- a/src/test/ui/print_type_sizes/generics.rs +++ b/src/test/ui/print_type_sizes/generics.rs @@ -72,7 +72,7 @@ pub fn f1(x: T) { fn start(_: isize, _: *const *const u8) -> isize { let _b: Pair = Pair::new(0, 0); let _s: Pair = Pair::new(SevenBytes::new(), SevenBytes::new()); - let _z: ZeroSized = ZeroSized; + let ref _z: ZeroSized = ZeroSized; f1::(SevenBytes::new()); 0 } -- cgit 1.4.1-3-g733a5 From a47fd3df89c267829d96748b3bdff305f20d27d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 13:49:54 -0500 Subject: make `#[unwind]` attribute specify expectations more clearly You can now choose between the following: - `#[unwind(allowed)]` - `#[unwind(aborts)]` Per rust-lang/rust#48251, the default is `#[unwind(allowed)]`, though I think we should change this eventually. --- src/libcore/panicking.rs | 3 ++- src/libpanic_unwind/gcc.rs | 3 ++- src/libpanic_unwind/lib.rs | 3 ++- src/libpanic_unwind/seh64_gnu.rs | 3 ++- src/libpanic_unwind/windows.rs | 9 +++++--- src/librustc_mir/build/mod.rs | 19 +++++++++++---- src/libstd/panicking.rs | 6 +++-- src/libsyntax/attr.rs | 45 ++++++++++++++++++++++++++++++++++++ src/libsyntax/diagnostic_list.rs | 27 ++++++++++++++++++++++ src/libsyntax/feature_gate.rs | 2 +- src/libunwind/libunwind.rs | 9 +++++--- src/test/codegen/extern-functions.rs | 2 +- src/test/run-pass/abort-on-c-abi.rs | 1 + 13 files changed, 113 insertions(+), 19 deletions(-) (limited to 'src/test/codegen') diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4170d91e5fc..94db0baa3f9 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,7 +64,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 63e44f71a3a..ca2fd561cad 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,7 +286,8 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 92e40e8f26d..a5cebc3e4d0 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,7 +112,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 0a9fa7d9a80..090cd095380 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,7 +108,8 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index a7e90071cea..50fba5faee7 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,18 +79,21 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 57059cd31a1..a325cfe3eaa 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -28,6 +28,7 @@ use std::mem; use std::u32; use syntax::abi::Abi; use syntax::ast; +use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; use syntax_pos::Span; use transform::MirSource; @@ -355,10 +356,9 @@ macro_rules! unpack { } fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_id: ast::NodeId, + fn_def_id: DefId, abi: Abi) -> bool { - // Not callable from C, so we can safely unwind through these if abi == Abi::Rust || abi == Abi::RustCall { return false; } @@ -370,9 +370,17 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. - if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; } + let attrs = &tcx.get_attrs(fn_def_id); + match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) { + None => { + // FIXME(rust-lang/rust#48251) -- Had to disable + // abort-on-panic for backwards compatibility reasons. + false + } - return true; + Some(UnwindAttr::Allowed) => false, + Some(UnwindAttr::Aborts) => true, + } } /////////////////////////////////////////////////////////////////////////// @@ -399,13 +407,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, safety, return_ty); + let fn_def_id = tcx.hir.local_def_id(fn_id); let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id); let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id); let mut block = START_BLOCK; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| { - if should_abort_on_panic(tcx, fn_id, abi) { + if should_abort_on_panic(tcx, fn_def_id, abi) { builder.schedule_abort(); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 161c3fc7113..454ac64735c 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,7 +55,8 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -315,7 +316,8 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d18d6f5e6bd..d0822b69aa6 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In }) } +#[derive(Copy, Clone, PartialEq)] +pub enum UnwindAttr { + Allowed, + Aborts, +} + +/// Determine what `#[unwind]` attribute is present in `attrs`, if any. +pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { + let syntax_error = |attr: &Attribute| { + mark_used(attr); + diagnostic.map(|d| { + span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); + }); + None + }; + + attrs.iter().fold(None, |ia, attr| { + if attr.path != "unwind" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { + MetaItemKind::Word => { + syntax_error(attr) + } + MetaItemKind::List(ref items) => { + mark_used(attr); + if items.len() != 1 { + syntax_error(attr) + } else if list_contains_name(&items[..], "allowed") { + Some(UnwindAttr::Allowed) + } else if list_contains_name(&items[..], "aborts") { + Some(UnwindAttr::Aborts) + } else { + syntax_error(attr) + } + } + _ => ia, + } + }) +} + /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. pub fn requests_inline(attrs: &[Attribute]) -> bool { match find_inline_attr(None, attrs) { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index d841281e485..84ab0336f16 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -342,6 +342,33 @@ fn main() { ``` "##, +E0633: r##" +The `unwind` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[unwind()] // error: expected one argument +pub extern fn something() {} + +fn main() {} +``` + +The `#[unwind]` attribute should be used as follows: + +- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function + should abort the process if it attempts to unwind. This is the safer + and preferred option. + +- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function + should be allowed to unwind. This can easily result in Undefined + Behavior (UB), so be careful. + +NB. The default behavior here is "allowed", but this is unspecified +and likely to change in the future. + +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b137f9570a..f1d0a70a22c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -233,7 +233,7 @@ declare_features! ( // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731)), - // allow `#[unwind]` + // allow `#[unwind(..)]` // rust runtime internal (active, unwind_attributes, "1.4.0", None), diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index e6fff7963f7..aa73b11fb38 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,7 +83,8 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -220,7 +221,8 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -229,7 +231,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs index 7ee31070b26..90ee0c75680 100644 --- a/src/test/codegen/extern-functions.rs +++ b/src/test/codegen/extern-functions.rs @@ -19,7 +19,7 @@ extern { fn extern_fn(); // CHECK-NOT: Function Attrs: nounwind // CHECK: declare void @unwinding_extern_fn - #[unwind] + #[unwind(allowed)] fn unwinding_extern_fn(); } diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs index 17661c0b120..5039c334f26 100644 --- a/src/test/run-pass/abort-on-c-abi.rs +++ b/src/test/run-pass/abort-on-c-abi.rs @@ -19,6 +19,7 @@ use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] extern "C" fn panic_in_ffi() { panic!("Test"); } -- cgit 1.4.1-3-g733a5 From 56a68285332000c858e9aeba7d66a4ec66ebff91 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 18 Feb 2018 15:05:24 -0800 Subject: Implement --remap-path-prefix Remove experimental -Zremap-path-prefix-from/to, and replace it with the stabilized --remap-path-prefix=from=to variant. This is an implementation for issue of #41555. --- src/doc/man/rustc.1 | 10 +++++ .../src/compiler-flags/remap-path-prefix.md | 37 ----------------- src/libproc_macro/lib.rs | 2 +- src/librustc/session/config.rs | 47 ++++++++++------------ src/librustc_metadata/encoder.rs | 2 +- src/libsyntax/codemap.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- .../auxiliary/remap_path_prefix_aux.rs | 2 +- src/test/codegen/remap_path_prefix/main.rs | 2 +- .../remapped_paths_cc/auxiliary/extern_crate.rs | 2 +- 10 files changed, 38 insertions(+), 70 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md (limited to 'src/test/codegen') diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 19f6cc9ac61..39d10539959 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -125,6 +125,16 @@ Print version info and exit. \fB\-v\fR, \fB\-\-verbose\fR Use verbose output. .TP +\fB\-\-remap\-path\-prefix\fR \fIfrom\fR=\fIto\fR +Remap source path prefixes in all output, including compiler diagnostics, debug information, +macro expansions, etc. The \fIfrom\fR=\fIto\fR parameter is scanned from right to left, so \fIfrom\fR +may contain '=', but \fIto\fR may not. + +This is useful for normalizing build products, for example by removing the current directory out of +pathnames emitted into the object files. The replacement is purely textual, with no consideration of +the current system's pathname syntax. For example \fI\-\-remap\-path\-prefix foo=bar\fR will +match \fBfoo/lib.rs\fR but not \fB./foo/lib.rs\fR. +.TP \fB\-\-extern\fR \fINAME\fR=\fIPATH\fR Specify where an external rust library is located. These should match \fIextern\fR declarations in the crate's source code. diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md deleted file mode 100644 index 8ca04d25325..00000000000 --- a/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md +++ /dev/null @@ -1,37 +0,0 @@ -# `remap-path-prefix` - -The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555) - ------------------------- - -The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option -pair allows to replace prefixes of any file paths the compiler emits in various -places. This is useful for bringing debuginfo paths into a well-known form and -for achieving reproducible builds independent of the directory the compiler was -executed in. All paths emitted by the compiler are affected, including those in -error messages. - -In order to map all paths starting with `/home/foo/my-project/src` to -`/sources/my-project`, one would invoke the compiler as follows: - -```text -rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project" -``` - -Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`, -for example, would then point debuggers to `/sources/my-project/foo/mod.rs` -instead of the original file. - -The options can be specified multiple times when multiple prefixes should be -mapped: - -```text -rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \ - -Zremap-path-prefix-to="/sources/my-project" \ - -Zremap-path-prefix-from="/home/foo/my-project/build-dir" \ - -Zremap-path-prefix-to="/stable-build-dir" -``` - -When the options are given multiple times, the nth `-from` will be matched up -with the nth `-to` and they can appear anywhere on the commandline. Mappings -specified later on the line will take precedence over earlier ones. diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 6768e0ade43..0f31ac15a45 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -316,7 +316,7 @@ impl SourceFile { /// If the code span associated with this `SourceFile` was generated by an external macro, this /// may not be an actual path on the filesystem. Use [`is_real`] to check. /// - /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on + /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on /// the command line, the path as given may not actually be valid. /// /// [`is_real`]: #method.is_real diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index cfbf233297c..1d554cb0d82 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -435,6 +435,9 @@ top_level_options!( // if we otherwise use the defaults of rustc. cli_forced_codegen_units: Option [UNTRACKED], cli_forced_thinlto_off: bool [UNTRACKED], + + // Remap source path prefixes in all output (messages, object files, debug, etc) + remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], } ); @@ -617,6 +620,7 @@ pub fn basic_options() -> Options { actually_rustdoc: false, cli_forced_codegen_units: None, cli_forced_thinlto_off: false, + remap_path_prefix: Vec::new(), } } @@ -635,11 +639,7 @@ impl Options { } pub fn file_path_mapping(&self) -> FilePathMapping { - FilePathMapping::new( - self.debugging_opts.remap_path_prefix_from.iter().zip( - self.debugging_opts.remap_path_prefix_to.iter() - ).map(|(src, dst)| (src.clone(), dst.clone())).collect() - ) + FilePathMapping::new(self.remap_path_prefix.clone()) } /// True if there will be an output file generated @@ -1269,10 +1269,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the optimization fuel quota for a crate"), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make Rustc print the total optimization fuel used by a crate"), - remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], - "add a source pattern to the file path remapping config"), - remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], - "add a mapping target to the file path remapping config"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable"), pre_link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], @@ -1595,6 +1591,7 @@ pub fn rustc_optgroups() -> Vec { `expanded` (crates expanded), or `expanded,identified` (fully parenthesized, AST nodes with IDs).", "TYPE"), + opt::multi_s("", "remap-path-prefix", "remap source names in output", "FROM=TO"), ]); opts } @@ -1718,23 +1715,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) output_types.insert(OutputType::Exe, None); } - let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len(); - let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len(); - - if remap_path_prefix_targets < remap_path_prefix_sources { - for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] { - early_error(error_format, - &format!("option `-Zremap-path-prefix-from='{}'` does not have \ - a corresponding `-Zremap-path-prefix-to`", source.display())) - } - } else if remap_path_prefix_targets > remap_path_prefix_sources { - for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] { - early_error(error_format, - &format!("option `-Zremap-path-prefix-to='{}'` does not have \ - a corresponding `-Zremap-path-prefix-from`", target.display())) - } - } - let mut cg = build_codegen_options(matches, error_format); let mut codegen_units = cg.codegen_units; let mut disable_thinlto = false; @@ -1968,6 +1948,20 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let crate_name = matches.opt_str("crate-name"); + let remap_path_prefix = matches.opt_strs("remap-path-prefix") + .into_iter() + .map(|remap| { + let mut parts = remap.rsplitn(2, '='); // reverse iterator + let to = parts.next(); + let from = parts.next(); + match (from, to) { + (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)), + _ => early_error(error_format, + "--remap-path-prefix must contain '=' between FROM and TO"), + } + }) + .collect(); + (Options { crate_types, optimize: opt_level, @@ -1995,6 +1989,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) actually_rustdoc: false, cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, + remap_path_prefix, }, cfg) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 78578ca179c..d140b135416 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -323,7 +323,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // paths because any relative paths are potentially relative to // a wrong directory. // However, if a path has been modified via - // `-Zremap-path-prefix` we assume the user has already set + // `--remap-path-prefix` we assume the user has already set // things up the way they want and don't touch the path values // anymore. match filemap.name { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index df5845f6c21..926548b6031 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -129,7 +129,7 @@ pub struct CodeMap { pub(super) files: RefCell>>, file_loader: Box, // This is used to apply the file path remapping as specified via - // -Zremap-path-prefix to all FileMaps allocated within this CodeMap. + // --remap-path-prefix to all FileMaps allocated within this CodeMap. path_mapping: FilePathMapping, stable_id_to_filemap: RefCell>>, /// In case we are in a doctest, replace all file names with the PathBuf, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 294506625bc..e3f1417456c 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -664,7 +664,7 @@ pub struct FileMap { /// originate from files has names between angle brackets by convention, /// e.g. `` pub name: FileName, - /// True if the `name` field above has been modified by -Zremap-path-prefix + /// True if the `name` field above has been modified by --remap-path-prefix pub name_was_remapped: bool, /// The unmapped path of the file that the source came from. /// Set to `None` if the FileMap was imported from an external crate. diff --git a/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs index 5543a091680..3ef0ff9ef06 100644 --- a/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs +++ b/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -// compile-flags: -g -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/aux-cwd -Zremap-path-prefix-from={{src-base}}/remap_path_prefix/auxiliary -Zremap-path-prefix-to=/the/aux-src +// compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src #[inline] pub fn some_aux_function() -> i32 { diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index ea0c9ad2b83..2f46b6c5d48 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -11,7 +11,7 @@ // ignore-windows // ignore-tidy-linelength -// compile-flags: -g -C no-prepopulate-passes -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src +// compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src // aux-build:remap_path_prefix_aux.rs extern crate remap_path_prefix_aux; diff --git a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs index 1483bf92c97..c80b334623b 100644 --- a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs +++ b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs @@ -12,7 +12,7 @@ //[rpass1] compile-flags: -g //[rpass2] compile-flags: -g -//[rpass3] compile-flags: -g -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src +//[rpass3] compile-flags: -g --remap-path-prefix={{src-base}}=/the/src #![feature(rustc_attrs)] #![crate_type="rlib"] -- cgit 1.4.1-3-g733a5 From 16ac85ce4dce1e185f2e6ce27df3833e07a9e502 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 4 Mar 2018 14:58:10 +0100 Subject: Remove useless powerpc64 entry from ARCH_TABLE, closes #47737 --- src/test/codegen/abi-main-signature-16bit-c-int.rs | 1 - src/test/codegen/fastcall-inreg.rs | 2 -- src/test/codegen/global_asm.rs | 2 -- src/test/codegen/global_asm_include.rs | 2 -- src/test/codegen/global_asm_x2.rs | 2 -- src/test/codegen/repr-transparent-aggregates-1.rs | 1 - src/tools/compiletest/src/util.rs | 1 - 7 files changed, 11 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index fbe2fd10e7a..1e02fe4befd 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -18,7 +18,6 @@ // ignore-hexagon // ignore-mips // ignore-powerpc -// ignore-powerpc64 // ignore-s390x // ignore-sparc // ignore-wasm32 diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index 346c5da8d1b..b24899cc363 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -25,8 +25,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs index 5bd0c1b4076..5661592d0c7 100644 --- a/src/test/codegen/global_asm.rs +++ b/src/test/codegen/global_asm.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs index 401b1fad566..d8b5db12404 100644 --- a/src/test/codegen/global_asm_include.rs +++ b/src/test/codegen/global_asm_include.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs index 8b59165e9e6..caa0506550d 100644 --- a/src/test/codegen/global_asm_x2.rs +++ b/src/test/codegen/global_asm_x2.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788c..655e67cf7ee 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -14,7 +14,6 @@ // ignore-mips // ignore-mips64 // ignore-powerpc -// ignore-powerpc64 // See repr-transparent.rs #![crate_type="lib"] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 3c9dae915b5..cf63cb2e5d9 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -43,7 +43,6 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("mips", "mips"), ("msp430", "msp430"), ("powerpc", "powerpc"), - ("powerpc64", "powerpc64"), ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"), -- cgit 1.4.1-3-g733a5 From 0595ff1009be0b4838b8efd0225c9601eff694eb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 Jan 2018 10:31:28 +0100 Subject: Codegen tests --- src/test/codegen/consts.rs | 10 +++++----- src/test/codegen/link_section.rs | 2 +- src/test/codegen/remap_path_prefix/main.rs | 2 +- src/test/compile-fail/issue-43105.rs | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index a75b8f3992d..13c037e96cb 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength #![crate_type = "lib"] @@ -19,12 +20,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @ref.{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@ref.[0-9]+]] = {{.*}}, align 4 -// CHECK: [[LOW_HIGH_REF:@const.[0-9]+]] = {{.*}} [[LOW_HIGH]] +// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] @@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 2, i1 false) *&E::A(0) } @@ -62,6 +62,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 4, i1 false) *&E::A(0) } diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 1879002e7f3..9c56a316b34 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,7 +12,7 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant i32 1, section ".test_one" +// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] pub static VAR1: u32 = 1; diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 2f46b6c5d48..4fb8c37558d 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -22,7 +22,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: internal constant [34 x i8] c"/the/src/remap_path_prefix/main.rs" +// CHECK: @byte_str.1 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/src/test/compile-fail/issue-43105.rs b/src/test/compile-fail/issue-43105.rs index fb419d751b4..c0af3b4b9e6 100644 --- a/src/test/compile-fail/issue-43105.rs +++ b/src/test/compile-fail/issue-43105.rs @@ -12,6 +12,7 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); //~^ ERROR calls in constants are limited to constant functions, struct and enum constructors +//~| ERROR constant evaluation error fn main() { match 1 { -- cgit 1.4.1-3-g733a5 From 208d7648331874fcdbdb144025a516f03db1eb69 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 22 Feb 2018 16:56:14 +0100 Subject: Adjust test which differs between 32 bit and 64 bit The differences are not part of what the test is testing, so they were simply removed. --- src/test/codegen/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 13c037e96cb..007fb7f4596 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 2, i1 false) +// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), *&E::A(0) } @@ -62,6 +62,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 4, i1 false) +// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), *&E::A(0) } -- cgit 1.4.1-3-g733a5 From 6f55819a1e6af80a4bec25dacf9391d81cc78652 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 25 Jan 2018 13:26:33 +0000 Subject: test: remove useless ignore-mips*el headers --- src/test/codegen/fastcall-inreg.rs | 2 -- src/test/codegen/global_asm.rs | 2 -- src/test/codegen/global_asm_include.rs | 2 -- src/test/codegen/global_asm_x2.rs | 2 -- 4 files changed, 8 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index b24899cc363..9bfe47d0a1f 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -21,9 +21,7 @@ // ignore-bpfeb // ignore-hexagon // ignore-mips -// ignore-mipsel // ignore-mips64 -// ignore-mips64el // ignore-msp430 // ignore-powerpc // ignore-r600 diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs index 5661592d0c7..94b69a6cab5 100644 --- a/src/test/codegen/global_asm.rs +++ b/src/test/codegen/global_asm.rs @@ -17,9 +17,7 @@ // ignore-bpfeb // ignore-hexagon // ignore-mips -// ignore-mipsel // ignore-mips64 -// ignore-mips64el // ignore-msp430 // ignore-powerpc // ignore-r600 diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs index d8b5db12404..c3688077f22 100644 --- a/src/test/codegen/global_asm_include.rs +++ b/src/test/codegen/global_asm_include.rs @@ -17,9 +17,7 @@ // ignore-bpfeb // ignore-hexagon // ignore-mips -// ignore-mipsel // ignore-mips64 -// ignore-mips64el // ignore-msp430 // ignore-powerpc // ignore-r600 diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs index caa0506550d..3b8fe43fa04 100644 --- a/src/test/codegen/global_asm_x2.rs +++ b/src/test/codegen/global_asm_x2.rs @@ -17,9 +17,7 @@ // ignore-bpfeb // ignore-hexagon // ignore-mips -// ignore-mipsel // ignore-mips64 -// ignore-mips64el // ignore-msp430 // ignore-powerpc // ignore-r600 -- cgit 1.4.1-3-g733a5 From dcc438d633f4f82467ce6408d05404959bb5dc43 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 25 Jan 2018 13:28:17 +0000 Subject: test: ignore mips64 in abi-main-signature-16bit-c-int.rs --- src/test/codegen/abi-main-signature-16bit-c-int.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index 1e02fe4befd..707531bf376 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -17,6 +17,7 @@ // ignore-asmjs // ignore-hexagon // ignore-mips +// ignore-mips64 // ignore-powerpc // ignore-s390x // ignore-sparc -- cgit 1.4.1-3-g733a5 From 59199ebe51d44e120dfd3f75dbcaf154afb70e13 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Fri, 9 Mar 2018 10:04:27 +0000 Subject: test: remove duplicate ignore-aarch64 from stack-probes test --- src/test/codegen/stack-probes.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 4a489f1edb3..45bcedd866f 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -11,7 +11,6 @@ // ignore-arm // ignore-aarch64 // ignore-powerpc -// ignore-aarch64 // ignore-wasm // ignore-emscripten // ignore-windows -- cgit 1.4.1-3-g733a5 From bceb94e8b7ba7efbeed95e080a753826cb18e89b Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Fri, 9 Mar 2018 10:05:05 +0000 Subject: test: ignore stack probe tests on mips* --- src/test/codegen/stack-probes.rs | 2 ++ src/test/run-pass/stack-probes-lto.rs | 2 ++ src/test/run-pass/stack-probes.rs | 2 ++ 3 files changed, 6 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 45bcedd866f..af400ff3bcb 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -10,6 +10,8 @@ // ignore-arm // ignore-aarch64 +// ignore-mips +// ignore-mips64 // ignore-powerpc // ignore-wasm // ignore-emscripten diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index 4deced1297b..e7fa3bc0a75 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -10,6 +10,8 @@ // ignore-arm // ignore-aarch64 +// ignore-mips +// ignore-mips64 // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index 4224a65ffd7..67b3962ee5f 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -10,6 +10,8 @@ // ignore-arm // ignore-aarch64 +// ignore-mips +// ignore-mips64 // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes -- cgit 1.4.1-3-g733a5 From e0863c5155138abeb2cae8d2b7bbd60dc700eef6 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Fri, 9 Mar 2018 10:14:33 +0000 Subject: test: ignore mips* in x86_mmx test --- src/test/codegen/x86_mmx.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index dc9f63c35db..30777c6214e 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -11,6 +11,8 @@ // ignore-arm // ignore-aarch64 // ignore-emscripten +// ignore-mips +// ignore-mips64 // compile-flags: -O #![feature(repr_simd)] -- cgit 1.4.1-3-g733a5 From fb806fd9db4012e0697d7d30cd034458e17e9fa0 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Fri, 9 Mar 2018 10:18:19 +0000 Subject: test: fix repr-transparent-aggregates test on mips64 Since #47964 was merged, 64-bit mips started passing all structures using 64-bit chunks regardless of their contents. The repr-transparent-aggregates tests needs updating to cope with this. --- src/test/codegen/repr-transparent-aggregates-2.rs | 1 + src/test/codegen/repr-transparent-aggregates-3.rs | 49 +++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/codegen/repr-transparent-aggregates-3.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index e6374928a5c..9605ded569e 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -12,6 +12,7 @@ // ignore-aarch64 // ignore-asmjs +// ignore-mips64 // ignore-s390x // ignore-wasm // ignore-x86 diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs new file mode 100644 index 00000000000..0c90239c9de --- /dev/null +++ b/src/test/codegen/repr-transparent-aggregates-3.rs @@ -0,0 +1,49 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +// only-mips64 +// See repr-transparent.rs + +#![crate_type="lib"] +#![feature(repr_transparent)] + + +#[repr(C)] +pub struct Big([u32; 16]); + +#[repr(transparent)] +pub struct BigW(Big); + +// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [8 x i64] +#[no_mangle] +pub extern fn test_Big(_: Big) -> Big { loop {} } + +// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [8 x i64] +#[no_mangle] +pub extern fn test_BigW(_: BigW) -> BigW { loop {} } + + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct BigUw(BigU); + +// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [8 x i64] +#[no_mangle] +pub extern fn test_BigU(_: BigU) -> BigU { loop {} } + +// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [8 x i64] +#[no_mangle] +pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } -- cgit 1.4.1-3-g733a5 From cca2604e6cf4bf303085d6f38731353621aa39cf Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sun, 18 Mar 2018 19:55:20 +0100 Subject: add codegen test --- src/test/codegen/simd-intrinsic-generic-select.rs | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/codegen/simd-intrinsic-generic-select.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-generic-select.rs b/src/test/codegen/simd-intrinsic-generic-select.rs new file mode 100644 index 00000000000..8a64d7437d8 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-generic-select.rs @@ -0,0 +1,35 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct b8x4(pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_select(x: T, a: U, b: U) -> U; +} + +// CHECK-LABEL: @select +#[no_mangle] +pub unsafe fn select(m: b8x4, a: f32x4, b: f32x4) -> f32x4 { + // CHECK: select <4 x i1> + simd_select(m, a, b) +} -- cgit 1.4.1-3-g733a5 From ca476dd8d3f0fa51f715d0de16800392cff82dd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 19 Mar 2018 01:34:32 +0000 Subject: Revert "Remove useless powerpc64 entry from ARCH_TABLE, closes #47737" This reverts commit 16ac85ce4dce1e185f2e6ce27df3833e07a9e502. --- src/test/codegen/abi-main-signature-16bit-c-int.rs | 1 + src/test/codegen/fastcall-inreg.rs | 2 ++ src/test/codegen/global_asm.rs | 2 ++ src/test/codegen/global_asm_include.rs | 2 ++ src/test/codegen/global_asm_x2.rs | 2 ++ src/test/codegen/repr-transparent-aggregates-1.rs | 1 + src/tools/compiletest/src/util.rs | 1 + 7 files changed, 11 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index 707531bf376..367d509cadf 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -19,6 +19,7 @@ // ignore-mips // ignore-mips64 // ignore-powerpc +// ignore-powerpc64 // ignore-s390x // ignore-sparc // ignore-wasm32 diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index 9bfe47d0a1f..d6dd3f356b5 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -23,6 +23,8 @@ // ignore-mips // ignore-mips64 // ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs index 94b69a6cab5..6b79e79fa00 100644 --- a/src/test/codegen/global_asm.rs +++ b/src/test/codegen/global_asm.rs @@ -19,6 +19,8 @@ // ignore-mips // ignore-mips64 // ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs index c3688077f22..3f73a1cabbf 100644 --- a/src/test/codegen/global_asm_include.rs +++ b/src/test/codegen/global_asm_include.rs @@ -19,6 +19,8 @@ // ignore-mips // ignore-mips64 // ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs index 3b8fe43fa04..3e118a50d45 100644 --- a/src/test/codegen/global_asm_x2.rs +++ b/src/test/codegen/global_asm_x2.rs @@ -19,6 +19,8 @@ // ignore-mips // ignore-mips64 // ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 655e67cf7ee..2eeed2b788c 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -14,6 +14,7 @@ // ignore-mips // ignore-mips64 // ignore-powerpc +// ignore-powerpc64 // See repr-transparent.rs #![crate_type="lib"] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 0e3fa25b13c..8c889cc4807 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -44,6 +44,7 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("mips", "mips"), ("msp430", "msp430"), ("powerpc", "powerpc"), + ("powerpc64", "powerpc64"), ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"), -- cgit 1.4.1-3-g733a5 From d6926ca12daa51fd786f233019ac539d1a732493 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 23 Mar 2018 23:47:22 -0700 Subject: Add a codegen test for exact_div intrinsic --- src/test/codegen/exact_div.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/codegen/exact_div.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/exact_div.rs b/src/test/codegen/exact_div.rs new file mode 100644 index 00000000000..9ba6c0c0006 --- /dev/null +++ b/src/test/codegen/exact_div.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::exact_div; + +// CHECK-LABEL: @exact_sdiv +#[no_mangle] +pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 { +// CHECK: sdiv exact + exact_div(x, y) +} + +// CHECK-LABEL: @exact_udiv +#[no_mangle] +pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 { +// CHECK: udiv exact + exact_div(x, y) +} -- cgit 1.4.1-3-g733a5 From d2cd57c8ff2116c2120da2668cee4ff2bf28315c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 09:49:46 +0100 Subject: add tests --- src/test/codegen/simd-intrinsic-float-minmax.rs | 40 +++++++++++++++++ src/test/run-fail/simd-intrinsic-float-minmax.rs | 55 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/test/codegen/simd-intrinsic-float-minmax.rs create mode 100644 src/test/run-fail/simd-intrinsic-float-minmax.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs new file mode 100644 index 00000000000..bebb4d37983 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -0,0 +1,40 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +// CHECK-LABEL: @fmin +#[no_mangle] +pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.minnum.v4f32 + simd_fmin(a, b) +} + +// FIXME(49261) +// // CHECK-LABEL: @fmax +// #[no_mangle] +// pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { +// // CHECK: call <4 x float> @llvm.maxnum.v4f32 +// simd_fmax(a, b) +// } diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs new file mode 100644 index 00000000000..32ee569d8fa --- /dev/null +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -0,0 +1,55 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// Test that the simd_f{min,max} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +fn main() { + let x = f32x4(1.0, 2.0, 3.0, 4.0); + let y = f32x4(2.0, 1.0, 4.0, 3.0); + let nan = ::std::f32::NAN; + let n = f32x4(nan, nan, nan, nan); + + unsafe { + let min0 = simd_fmin(x, y); + let min1 = simd_fmin(y, x); + assert_eq!(min0, min1); + let e = f32x4(1.0, 1.0, 3.0, 3.0); + assert_eq!(min0, e); + let minn = simd_fmin(x, n); + assert_eq!(minn, x); + let minn = simd_fmin(y, n); + assert_eq!(minn, y); + + // FIXME(49261) + let max0 = simd_fmax(x, y); + let max1 = simd_fmax(y, x); + assert_eq!(max0, max1); + let e = f32x4(2.0, 2.0, 4.0, 4.0); + assert_eq!(max0, e); + let maxn = simd_fmax(x, n); + assert_eq!(maxn, x); + let maxn = simd_fmax(y, n); + assert_eq!(maxn, y); + } +} -- cgit 1.4.1-3-g733a5 From 48fd903eae4b6b95c76f206c3c7f648aaf4f664d Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 18:01:35 +0100 Subject: set min-llvm-version 6.0, ignore-emscripten --- src/test/codegen/simd-intrinsic-float-minmax.rs | 3 +++ src/test/run-fail/simd-intrinsic-float-minmax.rs | 1 + 2 files changed, 4 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index bebb4d37983..8ad3ad762c2 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten +// min-llvm-version 6.0 + // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs index 32ee569d8fa..fad8fa48bc3 100644 --- a/src/test/run-fail/simd-intrinsic-float-minmax.rs +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-emscripten +// min-llvm-version 6.0 // Test that the simd_f{min,max} intrinsics produce the correct results. -- cgit 1.4.1-3-g733a5 From 56aaf344c444943f3c9cefe9d88ed27b43f0a731 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 26 Mar 2018 10:18:36 +0200 Subject: fix tests --- src/test/codegen/simd-intrinsic-float-minmax.rs | 4 ++-- src/test/run-fail/simd-intrinsic-float-minmax.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index 8ad3ad762c2..6663b841808 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -35,9 +35,9 @@ pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { } // FIXME(49261) -// // CHECK-LABEL: @fmax +// // C_HECK-LABEL: @fmax // #[no_mangle] // pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { -// // CHECK: call <4 x float> @llvm.maxnum.v4f32 +// // C_HECK: call <4 x float> @llvm.maxnum.v4f32 // simd_fmax(a, b) // } diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs index fad8fa48bc3..f4fb8e12250 100644 --- a/src/test/run-fail/simd-intrinsic-float-minmax.rs +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -10,6 +10,7 @@ // ignore-emscripten // min-llvm-version 6.0 +// error-pattern: panicked // Test that the simd_f{min,max} intrinsics produce the correct results. -- cgit 1.4.1-3-g733a5 From 7ce8191775b44d3773e28d647b5b17ec85508e16 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 19:51:49 -0500 Subject: Stabilize i128_type --- src/liballoc/benches/lib.rs | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/num/mod.rs | 6 ++-- src/libcore/tests/lib.rs | 2 +- src/libproc_macro/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_apfloat/lib.rs | 2 +- src/librustc_apfloat/tests/ieee.rs | 2 +- src/librustc_const_eval/lib.rs | 2 +- src/librustc_const_math/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_lint/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_resolve/lib.rs | 11 -------- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libserialize/lib.rs | 2 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 17 ++---------- src/libsyntax/lib.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- src/test/codegen/unchecked-float-casts.rs | 1 - src/test/mir-opt/lower_128bit_debug_test.rs | 1 - src/test/mir-opt/lower_128bit_test.rs | 1 - src/test/run-pass/float-int-invalid-const-cast.rs | 1 - src/test/run-pass/i128-ffi.rs | 2 -- src/test/run-pass/i128.rs | 2 +- src/test/run-pass/intrinsics-integer.rs | 2 +- src/test/run-pass/issue-38763.rs | 2 -- src/test/run-pass/issue-38987.rs | 1 - .../run-pass/next-power-of-two-overflow-debug.rs | 2 -- .../run-pass/next-power-of-two-overflow-ndebug.rs | 2 -- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/run-pass/u128.rs | 2 +- src/test/ui/feature-gate-i128_type.rs | 18 ------------ src/test/ui/feature-gate-i128_type.stderr | 19 ------------- src/test/ui/feature-gate-i128_type2.rs | 8 +++--- src/test/ui/feature-gate-i128_type2.stderr | 32 ---------------------- src/test/ui/lint-ctypes.rs | 2 +- src/test/ui/lint/type-overflow.rs | 2 -- 46 files changed, 37 insertions(+), 147 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type.rs delete mode 100644 src/test/ui/feature-gate-i128_type.stderr (limited to 'src/test/codegen') diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 2de0ffb4b26..09685d1bb40 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,7 @@ #![deny(warnings)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(test)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f914b1a93a9..19d64d8fea9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(generic_param_attrs)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4..11fecde3951 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,7 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..9ff42a6d4ea 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,8 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128_type)] -#![feature(i128)] + 170141183460469231731687303715884105727, "#![feature(i128)] # fn main() { ", " # }" } @@ -3493,8 +3492,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] -#![feature(i128)] + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] # fn main() { ", " diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c71669abb1..0b70f692403 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index d6e679bad48..716a2cc6cbb 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bb903c0627..061044cdf14 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,7 +53,7 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 565658804b0..2ee7bea8476 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,8 +46,8 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![feature(i128_type)] #![cfg_attr(stage0, feature(slice_patterns))] +#![cfg_attr(stage0, feature(i128_type))] #![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index ff46ee79c31..627d79724b2 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2b0775e8695..2620448927d 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,7 +23,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(macro_lifetime_matcher)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(from_ref)] extern crate arena; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 5555e727a95..a53055c7ce7 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -20,7 +20,7 @@ #![deny(warnings)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ff869072871..01f91e37db8 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,7 +26,7 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1152c9c574e..37ae64cef57 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -18,7 +18,7 @@ #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(stage0, feature(conservative_impl_trait))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 6adb950fe4e..5a33f566e90 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4639f7b2d28..d024adad9d0 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 902dd87c574..4af5ec9ae08 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 750839f8b00..a1f096b2a38 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -27,7 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2cb2c76c632..01eda71e9b6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3117,17 +3117,6 @@ impl<'a> Resolver<'a> { self.primitive_type_table.primitive_types .contains_key(&path[0].node.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; - match prim { - TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features_untracked().i128_type { - emit_feature_err(&self.session.parse_sess, - "i128_type", span, GateIssue::Language, - "128-bit type is unstable"); - - } - } - _ => {} - } PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 38adc603628..d89d19db63e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,7 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9e4addd1ed1..99de124c6e1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,7 +21,7 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(conservative_impl_trait))] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e466ef39234..8b3d5af3edd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,7 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e354252c15..ee952523462 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,7 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0b06c5d4d65..3cc5d7b81c3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -270,7 +270,7 @@ #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1bb369b551d..4e3c77d5e46 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,9 +303,6 @@ declare_features! ( // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), - // The `i128` type - (active, i128_type, "1.16.0", Some(35118), None), - // The `repr(i128)` annotation for enums (active, repr128, "1.16.0", Some(35118), None), @@ -564,6 +561,8 @@ declare_features! ( (accepted, universal_impl_trait, "1.26.0", Some(34511), None), // Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + // The `i128` type + (accepted, i128_type, "1.26.0", Some(35118), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1641,18 +1640,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { e.span, "yield syntax is experimental"); } - ast::ExprKind::Lit(ref lit) => { - if let ast::LitKind::Int(_, ref ty) = lit.node { - match *ty { - ast::LitIntType::Signed(ast::IntTy::I128) | - ast::LitIntType::Unsigned(ast::UintTy::U128) => { - gate_feature_post!(&self, i128_type, e.span, - "128-bit integers are not stable"); - } - _ => {} - } - } - } ast::ExprKind::Catch(_) => { gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 74f1ee373ec..2218b396685 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -24,7 +24,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(match_default_bindings)] #![feature(non_exhaustive)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 5a7b7e9ceca..eb345200f41 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs index c2fc2966170..87ebaaeec32 100644 --- a/src/test/codegen/unchecked-float-casts.rs +++ b/src/test/codegen/unchecked-float-casts.rs @@ -14,7 +14,6 @@ // -Z saturating-float-casts is not enabled. #![crate_type = "lib"] -#![feature(i128_type)] // CHECK-LABEL: @f32_to_u32 #[no_mangle] diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 1752445a141..d7586b1aa4b 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 4058eaef9b0..341682debeb 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs index d44f78922c7..f84432abbfa 100644 --- a/src/test/run-pass/float-int-invalid-const-cast.rs +++ b/src/test/run-pass/float-int-invalid-const-cast.rs @@ -10,7 +10,6 @@ // ignore-emscripten no i128 support -#![feature(i128_type)] #![deny(const_err)] use std::{f32, f64}; diff --git a/src/test/run-pass/i128-ffi.rs b/src/test/run-pass/i128-ffi.rs index d989210dd71..edf278cbf64 100644 --- a/src/test/run-pass/i128-ffi.rs +++ b/src/test/run-pass/i128-ffi.rs @@ -15,8 +15,6 @@ // ignore-windows // ignore-32bit -#![feature(i128_type)] - #[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn identity(f: u128) -> u128; diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index c3e43c92590..baf3b339984 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index cdfad51e648..7a8ff1befc7 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -10,7 +10,7 @@ // ignore-emscripten no i128 support -#![feature(intrinsics, i128_type)] +#![feature(intrinsics)] mod rusti { extern "rust-intrinsic" { diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs index 01cc8265a39..e038062ff9a 100644 --- a/src/test/run-pass/issue-38763.rs +++ b/src/test/run-pass/issue-38763.rs @@ -10,8 +10,6 @@ // ignore-emscripten -#![feature(i128_type)] - #[repr(C)] pub struct Foo(i128); diff --git a/src/test/run-pass/issue-38987.rs b/src/test/run-pass/issue-38987.rs index a513476d4a3..31a3b7233d8 100644 --- a/src/test/run-pass/issue-38987.rs +++ b/src/test/run-pass/issue-38987.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] fn main() { let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128; diff --git a/src/test/run-pass/next-power-of-two-overflow-debug.rs b/src/test/run-pass/next-power-of-two-overflow-debug.rs index 599c6dfd31d..2135b3f8764 100644 --- a/src/test/run-pass/next-power-of-two-overflow-debug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-debug.rs @@ -12,8 +12,6 @@ // ignore-wasm32-bare compiled with panic=abort by default // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - use std::panic; fn main() { diff --git a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs index f2312b70be6..b05c1863d90 100644 --- a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs @@ -11,8 +11,6 @@ // compile-flags: -C debug_assertions=no // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - fn main() { for i in 129..256 { assert_eq!((i as u8).next_power_of_two(), 0); diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index c8fa49c62a0..d1a0901bb3d 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, i128_type, stmt_expr_attributes)] +#![feature(test, i128, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 117e520155f..3531a961bef 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128, i128_type)] +#![feature(test, i128)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ebd43a86033..d649b3b74d3 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/ui/feature-gate-i128_type.rs b/src/test/ui/feature-gate-i128_type.rs deleted file mode 100644 index ddb49a3e5d9..00000000000 --- a/src/test/ui/feature-gate-i128_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn test2() { - 0i128; //~ ERROR 128-bit integers are not stable -} - -fn test2_2() { - 0u128; //~ ERROR 128-bit integers are not stable -} - diff --git a/src/test/ui/feature-gate-i128_type.stderr b/src/test/ui/feature-gate-i128_type.stderr deleted file mode 100644 index eb3b29f4f55..00000000000 --- a/src/test/ui/feature-gate-i128_type.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:12:5 - | -LL | 0i128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:16:5 - | -LL | 0u128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs index 8a7d316ed83..cd65b9d9223 100644 --- a/src/test/ui/feature-gate-i128_type2.rs +++ b/src/test/ui/feature-gate-i128_type2.rs @@ -10,20 +10,20 @@ // gate-test-i128_type -fn test1() -> i128 { //~ ERROR 128-bit type is unstable +fn test1() -> i128 { 0 } -fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable +fn test1_2() -> u128 { 0 } fn test3() { - let x: i128 = 0; //~ ERROR 128-bit type is unstable + let x: i128 = 0; } fn test3_2() { - let x: u128 = 0; //~ ERROR 128-bit type is unstable + let x: u128 = 0; } #[repr(u128)] diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index 23d4d6c98d9..fe4557899ac 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,35 +1,3 @@ -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:13:15 - | -LL | fn test1() -> i128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:17:17 - | -LL | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:22:12 - | -LL | let x: i128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:26:12 - | -LL | let x: u128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 77cb1ef0f51..85957831653 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, i128_type, repr_transparent)] +#![feature(libc, repr_transparent)] extern crate libc; diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs index 495989587e5..30e6fb2883b 100644 --- a/src/test/ui/lint/type-overflow.rs +++ b/src/test/ui/lint/type-overflow.rs @@ -10,8 +10,6 @@ // must-compile-successfully -#![feature(i128_type)] - fn main() { let error = 255i8; //~WARNING literal out of range for i8 -- cgit 1.4.1-3-g733a5 From bda718fd255237167f08198b0fc80ab0d484d58e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 26 Mar 2018 16:26:03 +0200 Subject: Allow niche-filling dataful variants to be represented as a ScalarPair --- src/librustc/ty/layout.rs | 19 +++++++++++++++---- src/test/codegen/function-arguments.rs | 6 ++++++ 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 029dd6f1fb4..5f9c305d92f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1517,10 +1517,21 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let offset = st[i].fields.offset(field_index) + offset; let size = st[i].size; - let abi = if offset.bytes() == 0 && niche.value.size(dl) == size { - Abi::Scalar(niche.clone()) - } else { - Abi::Aggregate { sized: true } + let abi = match st[i].abi { + Abi::Scalar(_) => Abi::Scalar(niche.clone()), + Abi::ScalarPair(ref first, ref second) => { + // We need to use scalar_unit to reset the + // valid range to the maximal one for that + // primitive, because only the niche is + // guaranteed to be initialised, not the + // other primitive. + if offset.bytes() == 0 { + Abi::ScalarPair(niche.clone(), scalar_unit(second.value)) + } else { + Abi::ScalarPair(scalar_unit(first.value), niche.clone()) + } + } + _ => Abi::Aggregate { sized: true }, }; return Ok(tcx.intern_layout(LayoutDetails { diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 0e98d3f9050..de302c69056 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -133,6 +133,12 @@ pub fn trait_borrow(_: &Drop) { pub fn trait_box(_: Box) { } +// CHECK: { i8*, i8* } @trait_option(i8* noalias %x.0, i8* %x.1) +#[no_mangle] +pub fn trait_option(x: Option>) -> Option> { + x +} + // CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias nonnull readonly %x.0, [[USIZE]] %x.1) #[no_mangle] pub fn return_slice(x: &[u16]) -> &[u16] { -- cgit 1.4.1-3-g733a5 From d032a4b079e9605bd95919db59c817422e0fdba8 Mon Sep 17 00:00:00 2001 From: Francis Gagné Date: Sat, 10 Mar 2018 19:04:40 -0500 Subject: Strengthen the repeat-trusted-len test Simply checking for the presence of `llvm.memset` is too brittle because this instrinsic can be used for seemingly trivial operations, such as zero-initializing a `RawVec`. --- src/test/codegen/repeat-trusted-len.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs index 43872f15d51..8b3294281e9 100644 --- a/src/test/codegen/repeat-trusted-len.rs +++ b/src/test/codegen/repeat-trusted-len.rs @@ -15,9 +15,14 @@ use std::iter; +// CHECK: @helper([[USIZE:i[0-9]+]] %arg0) +#[no_mangle] +pub fn helper(_: usize) { +} + // CHECK-LABEL: @repeat_take_collect #[no_mangle] pub fn repeat_take_collect() -> Vec { -// CHECK: call void @llvm.memset.p0i8 +// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}%{{[0-9]+}}, i8 42, [[USIZE]] 100000, i32 1, i1 false) iter::repeat(42).take(100000).collect() } -- cgit 1.4.1-3-g733a5 From b404ec4b4880db7f6aea23ebf778869dfd6ecf99 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 29 Mar 2018 10:25:32 -0700 Subject: Ignore stack-probes tests on powerpc/s390x too We only support stack probes on x86 and x86_64. Other arches are already ignored. --- src/test/codegen/stack-probes.rs | 1 + src/test/run-pass/stack-probes-lto.rs | 2 ++ src/test/run-pass/stack-probes.rs | 2 ++ 3 files changed, 5 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index af400ff3bcb..51ebc42a0dd 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -13,6 +13,7 @@ // ignore-mips // ignore-mips64 // ignore-powerpc +// ignore-s390x // ignore-wasm // ignore-emscripten // ignore-windows diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index e7fa3bc0a75..d1cb75909c1 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -12,6 +12,8 @@ // ignore-aarch64 // ignore-mips // ignore-mips64 +// ignore-powerpc +// ignore-s390x // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index 67b3962ee5f..78c5782be38 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -12,6 +12,8 @@ // ignore-aarch64 // ignore-mips // ignore-mips64 +// ignore-powerpc +// ignore-s390x // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes -- cgit 1.4.1-3-g733a5 From 94d36cf2948a999210516ff9001f93277f331d04 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 14:24:03 +0100 Subject: Make sure that generics are internalized in executables even with -Zshare-generics --- .../codegen/local-generics-in-exe-internalized.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/codegen/local-generics-in-exe-internalized.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/local-generics-in-exe-internalized.rs b/src/test/codegen/local-generics-in-exe-internalized.rs new file mode 100644 index 00000000000..162a025c302 --- /dev/null +++ b/src/test/codegen/local-generics-in-exe-internalized.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes -Zshare-generics=yes + +// Check that local generics are internalized if they are in the same CGU + +// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}} +pub fn foo(x: T, y: T) -> (T, T) { + (x, y) +} + +fn main() { + let _ = foo(0u8, 1u8); +} -- cgit 1.4.1-3-g733a5 From dab317f04f33358ff265123db6a27e43f30e2a33 Mon Sep 17 00:00:00 2001 From: "dragan.mladjenovic" Date: Tue, 3 Apr 2018 16:40:05 +0200 Subject: Small nits to make couple of tests pass on mips targets. --- src/test/codegen/link_section.rs | 6 ++++++ src/test/ui/asm-out-assign-imm.rs | 1 + src/test/ui/target-feature-wrong.rs | 1 + 3 files changed, 8 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 9c56a316b34..415ee6eb7ea 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -15,8 +15,14 @@ // CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] +#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "big")] +pub static VAR1: u32 = 0x01000000; + pub enum E { A(u32), B(f32) diff --git a/src/test/ui/asm-out-assign-imm.rs b/src/test/ui/asm-out-assign-imm.rs index 49084e01a15..055a169deda 100644 --- a/src/test/ui/asm-out-assign-imm.rs +++ b/src/test/ui/asm-out-assign-imm.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-mips #![feature(asm)] diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index 56acbed4721..080971f0347 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -12,6 +12,7 @@ // ignore-aarch64 // ignore-wasm // ignore-emscripten +// ignore-mips #![feature(target_feature)] -- cgit 1.4.1-3-g733a5 From 15d1c4d2139611fcb87a2c802bd015b5f4f0aed8 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sun, 4 Feb 2018 22:10:28 +1100 Subject: Implementation of `#[repr(packed(n))]` RFC 1399. --- .../src/language-features/repr-packed.md | 8 ++ src/librustc/session/code_stats.rs | 37 +++--- src/librustc/ty/layout.rs | 78 ++++++++----- src/librustc/ty/mod.rs | 30 +++-- src/librustc_typeck/check/mod.rs | 15 ++- src/librustc_typeck/diagnostics.rs | 5 +- src/libsyntax/attr.rs | 46 +++++--- src/libsyntax/feature_gate.rs | 19 +++- src/libsyntax_ext/deriving/generic/mod.rs | 10 +- src/test/codegen/packed.rs | 84 +++++++++++--- src/test/compile-fail/conflicting-repr-hints.rs | 11 ++ src/test/run-pass/align-struct.rs | 22 ++++ src/test/run-pass/auxiliary/packed.rs | 18 ++- src/test/run-pass/issue-48159.rs | 37 ++++++ src/test/run-pass/packed-struct-borrow-element.rs | 25 +++- src/test/run-pass/packed-struct-generic-size.rs | 33 +++++- src/test/run-pass/packed-struct-match.rs | 37 +++++- src/test/run-pass/packed-struct-size-xc.rs | 11 +- src/test/run-pass/packed-struct-size.rs | 126 ++++++++++++++++++--- src/test/run-pass/packed-struct-vec.rs | 99 ++++++++++++++-- src/test/run-pass/packed-tuple-struct-size.rs | 68 ++++++++--- src/test/run-pass/union/union-packed.rs | 112 ++++++++++++++---- src/test/ui/feature-gate-repr_packed.rs | 14 +++ src/test/ui/feature-gate-repr_packed.stderr | 11 ++ src/test/ui/print_type_sizes/packed.rs | 32 +++++- src/test/ui/print_type_sizes/packed.stdout | 18 ++- 26 files changed, 844 insertions(+), 162 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/repr-packed.md create mode 100644 src/test/run-pass/issue-48159.rs create mode 100644 src/test/ui/feature-gate-repr_packed.rs create mode 100644 src/test/ui/feature-gate-repr_packed.stderr (limited to 'src/test/codegen') diff --git a/src/doc/unstable-book/src/language-features/repr-packed.md b/src/doc/unstable-book/src/language-features/repr-packed.md new file mode 100644 index 00000000000..2dd763d04b0 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-packed.md @@ -0,0 +1,8 @@ +# `repr_packed` + +The tracking issue for this feature is [#33158] + +[#33158]: https://github.com/rust-lang/rust/issues/33158 + +------------------------ + diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index 64f405e0f24..df4060e71e5 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -62,6 +62,7 @@ pub struct TypeSizeInfo { pub type_description: String, pub align: u64, pub overall_size: u64, + pub packed: bool, pub opt_discr_size: Option, pub variants: Vec, } @@ -79,6 +80,7 @@ impl CodeStats { type_desc: S, align: Align, overall_size: Size, + packed: bool, opt_discr_size: Option, variants: Vec) { let info = TypeSizeInfo { @@ -86,6 +88,7 @@ impl CodeStats { type_description: type_desc.to_string(), align: align.abi(), overall_size: overall_size.bytes(), + packed: packed, opt_discr_size: opt_discr_size.map(|s| s.bytes()), variants, }; @@ -153,24 +156,26 @@ impl CodeStats { for field in fields.iter() { let FieldInfo { ref name, offset, size, align } = *field; - // Include field alignment in output only if it caused padding injection - if min_offset != offset { - if offset > min_offset { - let pad = offset - min_offset; - println!("print-type-size {}padding: {} bytes", - indent, pad); - println!("print-type-size {}field `.{}`: {} bytes, \ - alignment: {} bytes", - indent, name, size, align); - } else { - println!("print-type-size {}field `.{}`: {} bytes, \ - offset: {} bytes, \ - alignment: {} bytes", - indent, name, size, offset, align); - } - } else { + if offset > min_offset { + let pad = offset - min_offset; + println!("print-type-size {}padding: {} bytes", + indent, pad); + } + + if offset < min_offset { + // if this happens something is very wrong + println!("print-type-size {}field `.{}`: {} bytes, \ + offset: {} bytes, \ + alignment: {} bytes", + indent, name, size, offset, align); + } else if info.packed || offset == min_offset { println!("print-type-size {}field `.{}`: {} bytes", indent, name, size); + } else { + // Include field alignment in output only if it caused padding injection + println!("print-type-size {}field `.{}`: {} bytes, \ + alignment: {} bytes", + indent, name, size, align); } min_offset = offset + size; diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5f9c305d92f..6ed8730de6a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,7 +12,7 @@ pub use self::Integer::*; pub use self::Primitive::*; use session::{self, DataTypeKind, Session}; -use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; +use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{self, FloatTy, IntTy, UintTy}; use syntax::attr; @@ -344,8 +344,8 @@ impl AddAssign for Size { /// a maximum capacity of 231 - 1 or 2147483647. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Align { - abi: u8, - pref: u8, + abi_pow2: u8, + pref_pow2: u8, } impl Align { @@ -377,17 +377,17 @@ impl Align { }; Ok(Align { - abi: log2(abi)?, - pref: log2(pref)?, + abi_pow2: log2(abi)?, + pref_pow2: log2(pref)?, }) } pub fn abi(self) -> u64 { - 1 << self.abi + 1 << self.abi_pow2 } pub fn pref(self) -> u64 { - 1 << self.pref + 1 << self.pref_pow2 } pub fn abi_bits(self) -> u64 { @@ -400,15 +400,15 @@ impl Align { pub fn min(self, other: Align) -> Align { Align { - abi: cmp::min(self.abi, other.abi), - pref: cmp::min(self.pref, other.pref), + abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2), } } pub fn max(self, other: Align) -> Align { Align { - abi: cmp::max(self.abi, other.abi), - pref: cmp::max(self.pref, other.pref), + abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2), } } } @@ -974,6 +974,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { bug!("struct cannot be packed and aligned"); } + let pack = { + let pack = repr.pack as u64; + Align::from_bytes(pack, pack).unwrap() + }; + let mut align = if packed { dl.i8_align } else { @@ -984,8 +989,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut offsets = vec![Size::from_bytes(0); fields.len()]; let mut inverse_memory_index: Vec = (0..fields.len() as u32).collect(); - // Anything with repr(C) or repr(packed) doesn't optimize. - let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty(); + let mut optimize = !repr.inhibit_struct_field_reordering_opt(); if let StructKind::Prefixed(_, align) = kind { optimize &= align.abi() == 1; } @@ -997,6 +1001,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { fields.len() }; let optimizing = &mut inverse_memory_index[..end]; + let field_align = |f: &TyLayout| { + if packed { f.align.min(pack).abi() } else { f.align.abi() } + }; match kind { StructKind::AlwaysSized | StructKind::MaybeUnsized => { @@ -1004,11 +1011,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Place ZSTs first to avoid "interesting offsets", // especially with only one or two non-ZST fields. let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(f.align.abi())) - }) + (!f.is_zst(), cmp::Reverse(field_align(f))) + }); } StructKind::Prefixed(..) => { - optimizing.sort_by_key(|&x| fields[x as usize].align.abi()); + optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); } } } @@ -1022,7 +1029,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut offset = Size::from_bytes(0); if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - if !packed { + if packed { + let prefix_align = prefix_align.min(pack); + align = align.max(prefix_align); + } else { align = align.max(prefix_align); } offset = prefix_size.abi_align(prefix_align); @@ -1044,7 +1054,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - if !packed { + if packed { + let field_pack = field.align.min(pack); + offset = offset.abi_align(field_pack); + align = align.max(field_pack); + } + else { offset = offset.abi_align(field.align); align = align.max(field.align); } @@ -1377,7 +1392,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { bug!("Union cannot be packed and aligned"); } - let mut align = if def.repr.packed() { + let pack = { + let pack = def.repr.pack as u64; + Align::from_bytes(pack, pack).unwrap() + }; + + let mut align = if packed { dl.i8_align } else { dl.aggregate_align @@ -1393,7 +1413,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { for field in &variants[0] { assert!(!field.is_unsized()); - if !packed { + if packed { + let field_pack = field.align.min(pack); + align = align.max(field_pack); + } else { align = align.max(field.align); } size = cmp::max(size, field.size); @@ -1740,12 +1763,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) { // (delay format until we actually need it) - let record = |kind, opt_discr_size, variants| { + let record = |kind, packed, opt_discr_size, variants| { let type_desc = format!("{:?}", layout.ty); self.tcx.sess.code_stats.borrow_mut().record_type_size(kind, type_desc, layout.align, layout.size, + packed, opt_discr_size, variants); }; @@ -1758,7 +1782,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyClosure(..) => { debug!("print-type-size t: `{:?}` record closure", layout.ty); - record(DataTypeKind::Closure, None, vec![]); + record(DataTypeKind::Closure, false, None, vec![]); return; } @@ -1769,6 +1793,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }; let adt_kind = adt_def.adt_kind(); + let adt_packed = adt_def.repr.packed(); let build_variant_info = |n: Option, flds: &[ast::Name], @@ -1821,6 +1846,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); record(adt_kind.into(), + adt_packed, None, vec![build_variant_info(Some(variant_def.name), &fields, @@ -1828,7 +1854,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } else { // (This case arises for *empty* enums; so give it // zero variants.) - record(adt_kind.into(), None, vec![]); + record(adt_kind.into(), adt_packed, None, vec![]); } } @@ -1845,7 +1871,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { layout.for_variant(self, i)) }) .collect(); - record(adt_kind.into(), match layout.variants { + record(adt_kind.into(), adt_packed, match layout.variants { Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)), _ => None }, variant_infos); @@ -2518,8 +2544,8 @@ impl_stable_hash_for!(enum ::ty::layout::Primitive { }); impl_stable_hash_for!(struct ::ty::layout::Align { - abi, - pref + abi_pow2, + pref_pow2 }); impl_stable_hash_for!(struct ::ty::layout::Size { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5b1160f1420..33b59eda7ce 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1623,15 +1623,13 @@ bitflags! { #[derive(RustcEncodable, RustcDecodable, Default)] pub struct ReprFlags: u8 { const IS_C = 1 << 0; - const IS_PACKED = 1 << 1; - const IS_SIMD = 1 << 2; - const IS_TRANSPARENT = 1 << 3; + const IS_SIMD = 1 << 1; + const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. - const IS_LINEAR = 1 << 4; + const IS_LINEAR = 1 << 3; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | - ReprFlags::IS_PACKED.bits | ReprFlags::IS_SIMD.bits | ReprFlags::IS_LINEAR.bits; } @@ -1648,11 +1646,13 @@ impl_stable_hash_for!(struct ReprFlags { pub struct ReprOptions { pub int: Option, pub align: u32, + pub pack: u32, pub flags: ReprFlags, } impl_stable_hash_for!(struct ReprOptions { align, + pack, int, flags }); @@ -1662,11 +1662,19 @@ impl ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; let mut max_align = 0; + let mut min_pack = 0; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { flags.insert(match r { attr::ReprC => ReprFlags::IS_C, - attr::ReprPacked => ReprFlags::IS_PACKED, + attr::ReprPacked(pack) => { + min_pack = if min_pack > 0 { + cmp::min(pack, min_pack) + } else { + pack + }; + ReprFlags::empty() + }, attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { @@ -1685,7 +1693,7 @@ impl ReprOptions { if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, flags: flags } + ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags } } #[inline] @@ -1693,7 +1701,7 @@ impl ReprOptions { #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } #[inline] - pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) } + pub fn packed(&self) -> bool { self.pack > 0 } #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } #[inline] @@ -1709,6 +1717,12 @@ impl ReprOptions { pub fn inhibit_enum_layout_opt(&self) -> bool { self.c() || self.int.is_some() } + + /// Returns true if this `#[repr()]` should inhibit struct field reordering + /// optimizations, such as with repr(C) or repr(packed(1)). + pub fn inhibit_struct_field_reordering_opt(&self) -> bool { + !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) + } } impl<'a, 'gcx, 'tcx> AdtDef { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6c18f8d285d..a60ba4c6d16 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1553,8 +1553,19 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId } fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { - if tcx.adt_def(def_id).repr.packed() { - if tcx.adt_def(def_id).repr.align > 0 { + let repr = tcx.adt_def(def_id).repr; + if repr.packed() { + for attr in tcx.get_attrs(def_id).iter() { + for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { + if let attr::ReprPacked(pack) = r { + if pack != repr.pack { + struct_span_err!(tcx.sess, sp, E0634, + "type has conflicting packed representation hints").emit(); + } + } + } + } + if repr.align > 0 { struct_span_err!(tcx.sess, sp, E0587, "type has conflicting packed and align representation hints").emit(); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 79d7c8e7282..5a53c008f6c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4836,14 +4836,15 @@ register_diagnostics! { // E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0587, // struct has conflicting packed and align representation hints - E0588, // packed struct cannot transitively contain a `[repr(align)]` struct + E0587, // type has conflicting packed and align representation hints + E0588, // packed type cannot transitively contain a `[repr(align)]` type E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) E0640, // infer outlives E0627, // yield statement outside of generator literal E0632, // cannot provide explicit type parameters when `impl Trait` is used in // argument position. + E0634, // type has conflicting packed representaton hints E0641, // cannot cast to/from a pointer with an unknown kind E0645, // trait aliases not finished E0907, // type inside generator must be known in this context diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2812e1238e9..c68a743303a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -993,7 +993,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec let word = &*mi.ident.name.as_str(); let hint = match word { "C" => Some(ReprC), - "packed" => Some(ReprPacked), + "packed" => Some(ReprPacked(1)), "simd" => Some(ReprSimd), "transparent" => Some(ReprTransparent), _ => match int_type_of_word(word) { @@ -1009,27 +1009,41 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec acc.push(h); } } else if let Some((name, value)) = item.name_value_literal() { - if name == "align" { - recognised = true; - let mut align_error = None; - if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { - if align.is_power_of_two() { + let parse_alignment = |node: &ast::LitKind| -> Result { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + if literal.is_power_of_two() { // rustc::ty::layout::Align restricts align to <= 2147483647 - if align <= 2147483647 { - acc.push(ReprAlign(align as u32)); + if *literal <= 2147483647 { + Ok(*literal as u32) } else { - align_error = Some("larger than 2147483647"); + Err("larger than 2147483647") } } else { - align_error = Some("not a power of two"); + Err("not a power of two") } } else { - align_error = Some("not an unsuffixed integer"); - } - if let Some(align_error) = align_error { - span_err!(diagnostic, item.span, E0589, - "invalid `repr(align)` attribute: {}", align_error); + Err("not an unsuffixed integer") } + }; + + let mut literal_error = None; + if name == "align" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprAlign(literal)), + Err(message) => literal_error = Some(message) + }; + } + else if name == "packed" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprPacked(literal)), + Err(message) => literal_error = Some(message) + }; + } + if let Some(literal_error) = literal_error { + span_err!(diagnostic, item.span, E0589, + "invalid `repr(align)` attribute: {}", literal_error); } } if !recognised { @@ -1065,7 +1079,7 @@ fn int_type_of_word(s: &str) -> Option { pub enum ReprAttr { ReprInt(IntType), ReprC, - ReprPacked, + ReprPacked(u32), ReprSimd, ReprTransparent, ReprAlign(u32), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0a3cd66d897..df39757d1eb 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -432,6 +432,9 @@ declare_features! ( // Parentheses in patterns (active, pattern_parentheses, "1.26.0", None, None), + // Allows `#[repr(packed)]` attribute on structs + (active, repr_packed, "1.26.0", Some(33158), None), + // `use path as _;` and `extern crate c as _;` (active, underscore_imports, "1.26.0", Some(48216), None), @@ -1439,11 +1442,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - // allow attr_literals in #[repr(align(x))] - let mut is_repr_align = false; + // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))] + let mut allow_attr_literal = false; if attr.path == "repr" { if let Some(content) = attr.meta_item_list() { - is_repr_align = content.iter().any(|c| c.check_name("align")); + allow_attr_literal = content.iter().any( + |c| c.check_name("align") || c.check_name("packed")); } } @@ -1451,7 +1455,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { return } - if !is_repr_align { + if !allow_attr_literal { let meta = panictry!(attr.parse_meta(self.context.parse_sess)); if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, @@ -1535,6 +1539,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "the `#[repr(transparent)]` attribute \ is experimental"); } + if let Some((name, _)) = item.name_value_literal() { + if name == "packed" { + gate_feature_post!(&self, repr_packed, attr.span, + "the `#[repr(packed(n))]` attribute \ + is experimental"); + } + } } } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 4126ce79f35..66053e037e1 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -413,8 +413,12 @@ impl<'a> TraitDef<'a> { match *item { Annotatable::Item(ref item) => { let is_packed = item.attrs.iter().any(|attr| { - attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) - .contains(&attr::ReprPacked) + for r in attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) { + if let attr::ReprPacked(_) = r { + return true; + } + } + false }); let has_no_type_params = match item.node { ast::ItemKind::Struct(_, ref generics) | @@ -831,7 +835,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent => + attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent => continue, attr::ReprC => "i32", diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index 022f581278c..0693eae7d78 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -11,16 +11,23 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(repr_packed)] #[repr(packed)] -pub struct Packed { +pub struct Packed1 { dealign: u8, data: u32 } -// CHECK-LABEL: @write_pkd +#[repr(packed(2))] +pub struct Packed2 { + dealign: u8, + data: u32 +} + +// CHECK-LABEL: @write_pkd1 #[no_mangle] -pub fn write_pkd(pkd: &mut Packed) -> u32 { +pub fn write_pkd1(pkd: &mut Packed1) -> u32 { // CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 1 // CHECK: store i32 42, i32* %{{.*}}, align 1 let result = pkd.data; @@ -28,43 +35,94 @@ pub fn write_pkd(pkd: &mut Packed) -> u32 { result } +// CHECK-LABEL: @write_pkd2 +#[no_mangle] +pub fn write_pkd2(pkd: &mut Packed2) -> u32 { +// CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 2 +// CHECK: store i32 42, i32* %{{.*}}, align 2 + let result = pkd.data; + pkd.data = 42; + result +} + pub struct Array([i32; 8]); #[repr(packed)] -pub struct BigPacked { +pub struct BigPacked1 { + dealign: u8, + data: Array +} + +#[repr(packed(2))] +pub struct BigPacked2 { dealign: u8, data: Array } -// CHECK-LABEL: @call_pkd +// CHECK-LABEL: @call_pkd1 #[no_mangle] -pub fn call_pkd(f: fn() -> Array) -> BigPacked { +pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 1, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. - BigPacked { dealign: 0, data: f() } + BigPacked1 { dealign: 0, data: f() } +} + +// CHECK-LABEL: @call_pkd2 +#[no_mangle] +pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { +// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array +// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 2, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked2 { dealign: 0, data: f() } } #[repr(packed)] #[derive(Copy, Clone)] -pub struct PackedPair(u8, u32); +pub struct Packed1Pair(u8, u32); -// CHECK-LABEL: @pkd_pair +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2Pair(u8, u32); + +// CHECK-LABEL: @pkd1_pair #[no_mangle] -pub fn pkd_pair(pair1: &mut PackedPair, pair2: &mut PackedPair) { +pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) { // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 5, i32 1, i1 false) *pair2 = *pair1; } +// CHECK-LABEL: @pkd2_pair +#[no_mangle] +pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) { +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 6, i32 2, i1 false) + *pair2 = *pair1; +} + #[repr(packed)] #[derive(Copy, Clone)] -pub struct PackedNestedPair((u32, u32)); +pub struct Packed1NestedPair((u32, u32)); + +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2NestedPair((u32, u32)); -// CHECK-LABEL: @pkd_nested_pair +// CHECK-LABEL: @pkd1_nested_pair #[no_mangle] -pub fn pkd_nested_pair(pair1: &mut PackedNestedPair, pair2: &mut PackedNestedPair) { +pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) { // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 1, i1 false) *pair2 = *pair1; } + +// CHECK-LABEL: @pkd2_nested_pair +#[no_mangle] +pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) { +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 2, i1 false) + *pair2 = *pair1; +} + diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 8acc8b7bb1e..426f60c6b09 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![feature(repr_packed)] #[repr(C)] enum A { A } @@ -36,6 +37,16 @@ struct G(i32); //~ ERROR type has conflicting packed and align representation hi #[repr(packed)] struct H(i32); //~ ERROR type has conflicting packed and align representation hints +#[repr(packed, packed(2))] +struct I(i32); //~ ERROR type has conflicting packed representation hints + +#[repr(packed(2))] +#[repr(packed)] +struct J(i32); //~ ERROR type has conflicting packed representation hints + +#[repr(packed, packed(1))] +struct K(i32); + #[repr(packed, align(8))] union X { //~ ERROR type has conflicting packed and align representation hints i: i32 diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index dea8462705f..2b6a151574a 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(box_syntax)] +#![feature(repr_packed)] use std::mem; @@ -60,6 +61,18 @@ struct AlignContainsPacked { b: Packed, } +#[repr(C, packed(4))] +struct Packed4C { + a: u32, + b: u64, +} + +#[repr(align(16))] +struct AlignContainsPacked4C { + a: Packed4C, + b: u64, +} + // The align limit was originally smaller (2^15). // Check that it works with big numbers. #[repr(align(0x10000))] @@ -218,6 +231,15 @@ pub fn main() { assert_eq!(mem::size_of_val(&a), 16); assert!(is_aligned_to(&a, 16)); + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 32); + let a = AlignContainsPacked4C { a: Packed4C{ a: 1, b: 2 }, b: 3 }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 4); + assert_eq!(mem::align_of_val(&a.b), mem::align_of::()); + assert_eq!(mem::size_of_val(&a), 32); + assert!(is_aligned_to(&a, 16)); + let mut large = box AlignLarge { stuff: [0; 0x10000], }; diff --git a/src/test/run-pass/auxiliary/packed.rs b/src/test/run-pass/auxiliary/packed.rs index 86f5f93e3cf..828be41cd41 100644 --- a/src/test/run-pass/auxiliary/packed.rs +++ b/src/test/run-pass/auxiliary/packed.rs @@ -8,8 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] + #[repr(packed)] -pub struct S { +pub struct P1S5 { a: u8, b: u32 } + +#[repr(packed(2))] +pub struct P2S6 { + a: u8, + b: u32, + c: u8 +} + +#[repr(C, packed(2))] +pub struct P2CS8 { + a: u8, + b: u32, + c: u8 +} diff --git a/src/test/run-pass/issue-48159.rs b/src/test/run-pass/issue-48159.rs new file mode 100644 index 00000000000..ce4585607e9 --- /dev/null +++ b/src/test/run-pass/issue-48159.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_packed)] +#![allow(non_camel_case_types)] + +use std::mem; + +pub enum c_void {} + +type uintptr_t = usize; +type int16_t = u16; +type uint16_t = int16_t; +type uint32_t = u32; +type intptr_t = uintptr_t; + +#[repr(C)] +#[repr(packed(4))] +pub struct kevent { + pub ident: uintptr_t, + pub filter: int16_t, + pub flags: uint16_t, + pub fflags: uint32_t, + pub data: intptr_t, + pub udata: *mut c_void, +} + +fn main() { + assert_eq!(mem::align_of::(), 4); +} diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs index e725b25efee..c8a8643ed6b 100644 --- a/src/test/run-pass/packed-struct-borrow-element.rs +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -10,15 +10,36 @@ // ignore-emscripten weird assertion? +#![feature(repr_packed)] + #[repr(packed)] -struct Foo { +struct Foo1 { + bar: u8, + baz: usize +} + +#[repr(packed(2))] +struct Foo2 { + bar: u8, + baz: usize +} + +#[repr(C, packed(4))] +struct Foo4C { bar: u8, baz: usize } pub fn main() { - let foo = Foo { bar: 1, baz: 2 }; + let foo = Foo1 { bar: 1, baz: 2 }; let brw = unsafe { &foo.baz }; + assert_eq!(*brw, 2); + let foo = Foo2 { bar: 1, baz: 2 }; + let brw = unsafe { &foo.baz }; + assert_eq!(*brw, 2); + + let foo = Foo4C { bar: 1, baz: 2 }; + let brw = unsafe { &foo.baz }; assert_eq!(*brw, 2); } diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs index 4e1f62b28ab..127d873b2d9 100644 --- a/src/test/run-pass/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -8,18 +8,45 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S { +struct P1 { a: T, b: u8, c: S } +#[repr(packed(2))] +struct P2 { + a: T, + b: u8, + c: S +} + +#[repr(C, packed(4))] +struct P4C { + a: T, + b: u8, + c: S +} + +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} + pub fn main() { - assert_eq!(mem::size_of::>(), 3); + check!(P1::, 1, 3); + check!(P1::, 1, 11); + + check!(P2::, 1, 3); + check!(P2::, 2, 12); - assert_eq!(mem::size_of::>(), 11); + check!(P4C::, 1, 3); + check!(P4C::, 4, 12); } diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs index 3cd254014c1..c02d524d763 100644 --- a/src/test/run-pass/packed-struct-match.rs +++ b/src/test/run-pass/packed-struct-match.rs @@ -8,17 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] #[repr(packed)] -struct Foo { +struct Foo1 { + bar: u8, + baz: usize +} + +#[repr(packed(2))] +struct Foo2 { + bar: u8, + baz: usize +} + +#[repr(C, packed(4))] +struct Foo4C { bar: u8, baz: usize } pub fn main() { - let foo = Foo { bar: 1, baz: 2 }; - match foo { - Foo {bar, baz} => { + let foo1 = Foo1 { bar: 1, baz: 2 }; + match foo1 { + Foo1 {bar, baz} => { + assert_eq!(bar, 1); + assert_eq!(baz, 2); + } + } + + let foo2 = Foo2 { bar: 1, baz: 2 }; + match foo2 { + Foo2 {bar, baz} => { + assert_eq!(bar, 1); + assert_eq!(baz, 2); + } + } + + let foo4 = Foo4C { bar: 1, baz: 2 }; + match foo4 { + Foo4C {bar, baz} => { assert_eq!(bar, 1); assert_eq!(baz, 2); } diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs index 372693433db..48f34554ca1 100644 --- a/src/test/run-pass/packed-struct-size-xc.rs +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -15,6 +15,15 @@ extern crate packed; use std::mem; +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} + pub fn main() { - assert_eq!(mem::size_of::(), 5); + check!(packed::P1S5, 1, 5); + check!(packed::P2S6, 2, 6); + check!(packed::P2CS8, 2, 8); } diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs index 754a3573339..f8e23610fe2 100644 --- a/src/test/run-pass/packed-struct-size.rs +++ b/src/test/run-pass/packed-struct-size.rs @@ -7,44 +7,116 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S4 { +struct P1S4 { + a: u8, + b: [u8; 3], +} + +#[repr(packed(2))] +struct P2S4 { a: u8, b: [u8; 3], } #[repr(packed)] -struct S5 { +struct P1S5 { + a: u8, + b: u32 +} + +#[repr(packed(2))] +struct P2S2 { + a: u8, + b: u8 +} + +#[repr(packed(2))] +struct P2S6 { a: u8, b: u32 } +#[repr(packed(2))] +struct P2S12 { + a: u32, + b: u64 +} + #[repr(packed)] -struct S13 { +struct P1S13 { a: i64, b: f32, c: u8, } +#[repr(packed(2))] +struct P2S14 { + a: i64, + b: f32, + c: u8, +} + +#[repr(packed(4))] +struct P4S16 { + a: u8, + b: f32, + c: i64, + d: u16, +} + +#[repr(C, packed(4))] +struct P4CS20 { + a: u8, + b: f32, + c: i64, + d: u16, +} + enum Foo { Bar = 1, Baz = 2 } #[repr(packed)] -struct S3_Foo { +struct P1S3_Foo { + a: u8, + b: u16, + c: Foo +} + +#[repr(packed(2))] +struct P2_Foo { + a: Foo, +} + +#[repr(packed(2))] +struct P2S3_Foo { a: u8, b: u16, c: Foo } #[repr(packed)] -struct S7_Option { +struct P1S7_Option { + a: f32, + b: u8, + c: u16, + d: Option> +} + +#[repr(packed(2))] +struct P2_Option { + a: Option> +} + +#[repr(packed(2))] +struct P2S7_Option { a: f32, b: u8, c: u16, @@ -52,15 +124,41 @@ struct S7_Option { } // Placing packed structs in statics should work -static TEST_S4: S4 = S4 { a: 1, b: [2, 3, 4] }; -static TEST_S5: S5 = S5 { a: 3, b: 67 }; -static TEST_S3_Foo: S3_Foo = S3_Foo { a: 1, b: 2, c: Foo::Baz }; +static TEST_P1S4: P1S4 = P1S4 { a: 1, b: [2, 3, 4] }; +static TEST_P1S5: P1S5 = P1S5 { a: 3, b: 67 }; +static TEST_P1S3_Foo: P1S3_Foo = P1S3_Foo { a: 1, b: 2, c: Foo::Baz }; +static TEST_P2S2: P2S2 = P2S2 { a: 1, b: 2 }; +static TEST_P2S4: P2S4 = P2S4 { a: 1, b: [2, 3, 4] }; +static TEST_P2S6: P2S6 = P2S6 { a: 1, b: 2 }; +static TEST_P2S12: P2S12 = P2S12 { a: 1, b: 2 }; +static TEST_P4S16: P4S16 = P4S16 { a: 1, b: 2.0, c: 3, d: 4 }; +static TEST_P4CS20: P4CS20 = P4CS20 { a: 1, b: 2.0, c: 3, d: 4 }; +fn align_to(value: usize, align: usize) -> usize { + (value + (align - 1)) & !(align - 1) +} + +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} pub fn main() { - assert_eq!(mem::size_of::(), 4); - assert_eq!(mem::size_of::(), 5); - assert_eq!(mem::size_of::(), 13); - assert_eq!(mem::size_of::(), 3 + mem::size_of::()); - assert_eq!(mem::size_of::(), 7 + mem::size_of::>>()); + check!(P1S4, 1, 4); + check!(P1S5, 1, 5); + check!(P1S13, 1, 13); + check!(P1S3_Foo, 1, 3 + mem::size_of::()); + check!(P1S7_Option, 1, 7 + mem::size_of::>>()); + + check!(P2S2, 1, 2); + check!(P2S4, 1, 4); + check!(P2S6, 2, 6); + check!(P2S12, 2, 12); + check!(P2S14, 2, 14); + check!(P4S16, 4, 16); + check!(P4CS20, 4, 20); + check!(P2S3_Foo, 2, align_to(3 + mem::size_of::(), 2)); + check!(P2S7_Option, 2, align_to(7 + mem::size_of::(), 2)); } diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 57407b84223..9d8b3d0d074 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -8,28 +8,80 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] + use std::fmt; use std::mem; #[repr(packed)] #[derive(Copy, Clone)] -struct Foo { +struct Foo1 { bar: u8, baz: u64 } -impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { +impl PartialEq for Foo1 { + fn eq(&self, other: &Foo1) -> bool { self.bar == other.bar && self.baz == other.baz } } -impl fmt::Debug for Foo { +impl fmt::Debug for Foo1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let bar = self.bar; let baz = self.baz; - f.debug_struct("Foo") + f.debug_struct("Foo1") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + +#[repr(packed(2))] +#[derive(Copy, Clone)] +struct Foo2 { + bar: u8, + baz: u64 +} + +impl PartialEq for Foo2 { + fn eq(&self, other: &Foo2) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo2") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + +#[repr(C, packed(4))] +#[derive(Copy, Clone)] +struct Foo4C { + bar: u8, + baz: u64 +} + +impl PartialEq for Foo4C { + fn eq(&self, other: &Foo4C) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo4C { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo4C") .field("bar", &bar) .field("baz", &baz) .finish() @@ -37,15 +89,42 @@ impl fmt::Debug for Foo { } pub fn main() { - let foos = [Foo { bar: 1, baz: 2 }; 10]; + let foo1s = [Foo1 { bar: 1, baz: 2 }; 10]; + + assert_eq!(mem::align_of::<[Foo1; 10]>(), 1); + assert_eq!(mem::size_of::<[Foo1; 10]>(), 90); + + for i in 0..10 { + assert_eq!(foo1s[i], Foo1 { bar: 1, baz: 2}); + } + + for &foo in &foo1s { + assert_eq!(foo, Foo1 { bar: 1, baz: 2 }); + } + + let foo2s = [Foo2 { bar: 1, baz: 2 }; 10]; + + assert_eq!(mem::align_of::<[Foo2; 10]>(), 2); + assert_eq!(mem::size_of::<[Foo2; 10]>(), 100); + + for i in 0..10 { + assert_eq!(foo2s[i], Foo2 { bar: 1, baz: 2}); + } + + for &foo in &foo2s { + assert_eq!(foo, Foo2 { bar: 1, baz: 2 }); + } + + let foo4s = [Foo4C { bar: 1, baz: 2 }; 10]; - assert_eq!(mem::size_of::<[Foo; 10]>(), 90); + assert_eq!(mem::align_of::<[Foo4C; 10]>(), 4); + assert_eq!(mem::size_of::<[Foo4C; 10]>(), 120); for i in 0..10 { - assert_eq!(foos[i], Foo { bar: 1, baz: 2}); + assert_eq!(foo4s[i], Foo4C { bar: 1, baz: 2}); } - for &foo in &foos { - assert_eq!(foo, Foo { bar: 1, baz: 2 }); + for &foo in &foo4s { + assert_eq!(foo, Foo4C { bar: 1, baz: 2 }); } } diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs index b0c8684cfe3..9def6ac28e5 100644 --- a/src/test/run-pass/packed-tuple-struct-size.rs +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -8,18 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S4(u8,[u8; 3]); +struct P1S4(u8,[u8; 3]); + +#[repr(packed(2))] +struct P2S4(u8,[u8; 3]); #[repr(packed)] -struct S5(u8, u32); +struct P1S5(u8, u32); + +#[repr(packed(2))] +struct P2S6(u8, u32); #[repr(packed)] -struct S13(i64, f32, u8); +struct P1S13(i64, f32, u8); + +#[repr(packed(2))] +struct P2S14(i64, f32, u8); + +#[repr(packed(4))] +struct P4S16(u8, f32, i64, u16); + +#[repr(C, packed(4))] +struct P4CS20(u8, f32, i64, u16); enum Foo { Bar = 1, @@ -27,21 +42,46 @@ enum Foo { } #[repr(packed)] -struct S3_Foo(u8, u16, Foo); +struct P1S3_Foo(u8, u16, Foo); + +#[repr(packed(2))] +struct P2_Foo(Foo); + +#[repr(packed(2))] +struct P2S3_Foo(u8, u16, Foo); #[repr(packed)] -struct S7_Option(f32, u8, u16, Option>); +struct P1S7_Option(f32, u8, u16, Option>); -pub fn main() { - assert_eq!(mem::size_of::(), 4); +#[repr(packed(2))] +struct P2_Option(Option>); + +#[repr(packed(2))] +struct P2S7_Option(f32, u8, u16, Option>); - assert_eq!(mem::size_of::(), 5); +fn align_to(value: usize, align: usize) -> usize { + (value + (align - 1)) & !(align - 1) +} - assert_eq!(mem::size_of::(), 13); +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} - assert_eq!(mem::size_of::(), - 3 + mem::size_of::()); +pub fn main() { + check!(P1S4, 1, 4); + check!(P1S5, 1, 5); + check!(P1S13, 1, 13); + check!(P1S3_Foo, 1, 3 + mem::size_of::()); + check!(P1S7_Option, 1, 7 + mem::size_of::>>()); - assert_eq!(mem::size_of::(), - 7 + mem::size_of::>>()); + check!(P2S4, 1, 4); + check!(P2S6, 2, 6); + check!(P2S14, 2, 14); + check!(P4S16, 4, 16); + check!(P4CS20, 4, 20); + check!(P2S3_Foo, 2, align_to(3 + mem::size_of::(), 2)); + check!(P2S7_Option, 2, align_to(7 + mem::size_of::(), 2)); } diff --git a/src/test/run-pass/union/union-packed.rs b/src/test/run-pass/union/union-packed.rs index 6a61280823e..61bb04fece0 100644 --- a/src/test/run-pass/union/union-packed.rs +++ b/src/test/run-pass/union/union-packed.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(untagged_unions)] +#![feature(repr_packed)] use std::mem::{size_of, size_of_val, align_of, align_of_val}; @@ -18,7 +19,13 @@ struct S { } #[repr(packed)] -struct Sp { +struct Sp1 { + a: u16, + b: [u8; 3], +} + +#[repr(packed(2))] +struct Sp2 { a: u16, b: [u8; 3], } @@ -29,15 +36,30 @@ union U { } #[repr(packed)] -union Up { +union Up1 { + a: u16, + b: [u8; 3], +} + +#[repr(packed(2))] +union Up2 { + a: u16, + b: [u8; 3], +} + +#[repr(C, packed(4))] +union Up4c { a: u16, b: [u8; 3], } const CS: S = S { a: 0, b: [0, 0, 0] }; -const CSP: Sp = Sp { a: 0, b: [0, 0, 0] }; +const CSP1: Sp1 = Sp1 { a: 0, b: [0, 0, 0] }; +const CSP2: Sp2 = Sp2 { a: 0, b: [0, 0, 0] }; const CU: U = U { b: [0, 0, 0] }; -const CUP: Up = Up { b: [0, 0, 0] }; +const CUP1: Up1 = Up1 { b: [0, 0, 0] }; +const CUP2: Up2 = Up2 { b: [0, 0, 0] }; +const CUP4C: Up4c = Up4c { b: [0, 0, 0] }; fn main() { let s = S { a: 0, b: [0, 0, 0] }; @@ -48,13 +70,21 @@ fn main() { assert_eq!(align_of_val(&s), 2); assert_eq!(align_of_val(&CS), 2); - let sp = Sp { a: 0, b: [0, 0, 0] }; - assert_eq!(size_of::(), 5); - assert_eq!(size_of_val(&sp), 5); - assert_eq!(size_of_val(&CSP), 5); - assert_eq!(align_of::(), 1); - assert_eq!(align_of_val(&sp), 1); - assert_eq!(align_of_val(&CSP), 1); + let sp1 = Sp1 { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 5); + assert_eq!(size_of_val(&sp1), 5); + assert_eq!(size_of_val(&CSP1), 5); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&sp1), 1); + assert_eq!(align_of_val(&CSP1), 1); + + let sp2 = Sp2 { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 6); + assert_eq!(size_of_val(&sp2), 6); + assert_eq!(size_of_val(&CSP2), 6); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&sp2), 2); + assert_eq!(align_of_val(&CSP2), 2); let u = U { b: [0, 0, 0] }; assert_eq!(size_of::(), 4); @@ -64,19 +94,35 @@ fn main() { assert_eq!(align_of_val(&u), 2); assert_eq!(align_of_val(&CU), 2); - let up = Up { b: [0, 0, 0] }; - assert_eq!(size_of::(), 3); - assert_eq!(size_of_val(&up), 3); - assert_eq!(size_of_val(&CUP), 3); - assert_eq!(align_of::(), 1); - assert_eq!(align_of_val(&up), 1); - assert_eq!(align_of_val(&CUP), 1); + let Up1 = Up1 { b: [0, 0, 0] }; + assert_eq!(size_of::(), 3); + assert_eq!(size_of_val(&Up1), 3); + assert_eq!(size_of_val(&CUP1), 3); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&Up1), 1); + assert_eq!(align_of_val(&CUP1), 1); + + let up2 = Up2 { b: [0, 0, 0] }; + assert_eq!(size_of::(), 4); + assert_eq!(size_of_val(&up2), 4); + assert_eq!(size_of_val(&CUP2), 4); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&up2), 2); + assert_eq!(align_of_val(&CUP2), 2); + + let up4c = Up4c { b: [0, 0, 0] }; + assert_eq!(size_of::(), 4); + assert_eq!(size_of_val(&up4c), 4); + assert_eq!(size_of_val(&CUP4C), 4); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&up4c), 2); + assert_eq!(align_of_val(&CUP4C), 2); hybrid::check_hybrid(); } mod hybrid { - use std::mem::size_of; + use std::mem::{size_of, align_of}; #[repr(packed)] struct S1 { @@ -96,9 +142,37 @@ mod hybrid { u: U, } + #[repr(C, packed(2))] + struct S1C { + a: u16, + b: u8, + } + + #[repr(C, packed(2))] + union UC { + s: S1, + c: u16, + } + + #[repr(C, packed(2))] + struct S2C { + d: u8, + u: UC, + } + pub fn check_hybrid() { + assert_eq!(align_of::(), 1); assert_eq!(size_of::(), 3); + assert_eq!(align_of::(), 1); assert_eq!(size_of::(), 3); + assert_eq!(align_of::(), 1); assert_eq!(size_of::(), 4); + + assert_eq!(align_of::(), 2); + assert_eq!(size_of::(), 4); + assert_eq!(align_of::(), 2); + assert_eq!(size_of::(), 4); + assert_eq!(align_of::(), 2); + assert_eq!(size_of::(), 6); } } diff --git a/src/test/ui/feature-gate-repr_packed.rs b/src/test/ui/feature-gate-repr_packed.rs new file mode 100644 index 00000000000..12bb152b467 --- /dev/null +++ b/src/test/ui/feature-gate-repr_packed.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental +struct Foo(u64); + +fn main() {} diff --git a/src/test/ui/feature-gate-repr_packed.stderr b/src/test/ui/feature-gate-repr_packed.stderr new file mode 100644 index 00000000000..d0faf9d90bd --- /dev/null +++ b/src/test/ui/feature-gate-repr_packed.stderr @@ -0,0 +1,11 @@ +error[E0658]: the `#[repr(packed(n))]` attribute is experimental (see issue #33158) + --> $DIR/feature-gate-repr_packed.rs:11:1 + | +LL | #[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental + | ^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(repr_packed)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs index a4288f67899..5d8c9326258 100644 --- a/src/test/ui/print_type_sizes/packed.rs +++ b/src/test/ui/print_type_sizes/packed.rs @@ -21,10 +21,34 @@ #![allow(dead_code)] #![feature(start)] +#![feature(repr_packed)] #[derive(Default)] #[repr(packed)] -struct Packed { +struct Packed1 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +struct Packed2 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +#[repr(C)] +struct Packed2C { a: u8, b: u8, g: i32, @@ -45,7 +69,9 @@ struct Padded { #[start] fn start(_: isize, _: *const *const u8) -> isize { - let _c: Packed = Default::default(); - let _d: Padded = Default::default(); + let _c: Packed1 = Default::default(); + let _d: Packed2 = Default::default(); + let _e: Packed2C = Default::default(); + let _f: Padded = Default::default(); 0 } diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout index 83fd333c9c7..58e1bac9eb7 100644 --- a/src/test/ui/print_type_sizes/packed.stdout +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -1,3 +1,12 @@ +print-type-size type: `Packed2C`: 12 bytes, alignment: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size padding: 1 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 1 bytes print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes print-type-size field `.g`: 4 bytes print-type-size field `.h`: 2 bytes @@ -6,10 +15,17 @@ print-type-size field `.b`: 1 bytes print-type-size field `.c`: 1 bytes print-type-size field `.d`: 1 bytes print-type-size end padding: 2 bytes -print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes +print-type-size type: `Packed1`: 10 bytes, alignment: 1 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes print-type-size field `.g`: 4 bytes print-type-size field `.c`: 1 bytes print-type-size field `.h`: 2 bytes print-type-size field `.d`: 1 bytes +print-type-size type: `Packed2`: 10 bytes, alignment: 2 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.d`: 1 bytes -- cgit 1.4.1-3-g733a5 From f7439a5a4565b86b934610aafa9c69b9c53b672b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 19 Apr 2018 15:17:34 -0700 Subject: rustc: Always emit `uwtable` on Android Long ago (#40549) we enabled the `uwtable` attribute on Windows by default (even with `-C panic=abort`) to allow unwinding binaries for [stack unwinding information][winstack]. It looks like this same issue is [plaguing][arm1] Gecko's Android platforms [as well][arm2]. This commit applies the same fix as #40549 except that this time it's applied for all Android targets. Generating a `-C panic=abort` binary for `armv7-linux-androideabi` before this commit generated a number of `cantunwind` functions (detected with `readelf -u`) but after this commit they all list appropriate unwind information. Closes #49867 [winstack]: https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 [arm1]: https://bugzilla.mozilla.org/show_bug.cgi?id=1453220 [arm2]: https://bugzilla.mozilla.org/show_bug.cgi?id=1451741 --- src/librustc_back/target/android_base.rs | 1 + src/librustc_back/target/mod.rs | 8 ++++++++ src/librustc_back/target/windows_base.rs | 1 + src/librustc_back/target/windows_msvc_base.rs | 1 + src/librustc_trans/base.rs | 2 +- src/test/codegen/nounwind.rs | 1 + 6 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src/test/codegen') diff --git a/src/librustc_back/target/android_base.rs b/src/librustc_back/target/android_base.rs index 49baa1b96ce..3660bf7bea9 100644 --- a/src/librustc_back/target/android_base.rs +++ b/src/librustc_back/target/android_base.rs @@ -20,5 +20,6 @@ pub fn opts() -> TargetOptions { base.is_like_android = true; base.position_independent_executables = true; base.has_elf_tls = false; + base.requires_uwtable = true; base } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 592b27ac641..e46266b576e 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -481,6 +481,11 @@ pub struct TargetOptions { /// Whether a .debug_gdb_scripts section will be added to the output object file pub emit_debug_gdb_scripts: bool, + + /// Whether or not to unconditionally `uwtable` attributes on functions, + /// typically because the platform needs to unwind for things like stack + /// unwinders. + pub requires_uwtable: bool, } impl Default for TargetOptions { @@ -554,6 +559,7 @@ impl Default for TargetOptions { default_hidden_visibility: false, embed_bitcode: false, emit_debug_gdb_scripts: true, + requires_uwtable: false, } } } @@ -804,6 +810,7 @@ impl Target { key!(default_hidden_visibility, bool); key!(embed_bitcode, bool); key!(emit_debug_gdb_scripts, bool); + key!(requires_uwtable, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -1008,6 +1015,7 @@ impl ToJson for Target { target_option_val!(default_hidden_visibility); target_option_val!(embed_bitcode); target_option_val!(emit_debug_gdb_scripts); + target_option_val!(requires_uwtable); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index 971b21e062f..4b4fb27caa8 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -103,6 +103,7 @@ pub fn opts() -> TargetOptions { custom_unwind_resume: true, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + requires_uwtable: true, .. Default::default() } diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index 06e879bec34..fee5a0284c8 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -35,6 +35,7 @@ pub fn opts() -> TargetOptions { crt_static_respected: true, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + requires_uwtable: true, .. Default::default() } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1da6f25fd63..a4e1b7f2925 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -492,7 +492,7 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc // You can also find more info on why Windows is whitelisted here in: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if !cx.sess().no_landing_pads() || - cx.sess().target.target.options.is_like_windows { + cx.sess().target.target.options.requires_uwtable { attributes::emit_uwtable(lldecl, true); } diff --git a/src/test/codegen/nounwind.rs b/src/test/codegen/nounwind.rs index 9fea907d3c8..6863b1f2792 100644 --- a/src/test/codegen/nounwind.rs +++ b/src/test/codegen/nounwind.rs @@ -11,6 +11,7 @@ // aux-build:nounwind.rs // compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a // ignore-windows +// ignore-android #![crate_type = "lib"] -- cgit 1.4.1-3-g733a5 From 3ca6ad922eb6d8c3139d961c844a0194eaf58770 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 27 Mar 2018 16:44:03 +0200 Subject: Use ScalarPair for tagged enums --- src/librustc/ty/layout.rs | 81 ++++++++++++++++++++++++++++++---- src/test/codegen/align-struct.rs | 3 +- src/test/codegen/function-arguments.rs | 12 +++++ src/test/codegen/lifetime_start_end.rs | 8 ++-- 4 files changed, 90 insertions(+), 14 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 77e2e9447f1..cfed0839acb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1622,7 +1622,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } // Create the set of structs that represent each variant. - let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| { + let mut layout_variants = variants.iter().enumerate().map(|(i, field_layouts)| { let mut st = univariant_uninterned(&field_layouts, &def.repr, StructKind::Prefixed(min_ity.size(), prefix_align))?; st.variants = Variants::Single { index: i }; @@ -1683,7 +1683,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Patch up the variants' first few fields. let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); - for variant in &mut variants { + for variant in &mut layout_variants { if variant.abi == Abi::Uninhabited { continue; } @@ -1710,15 +1710,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { value: Int(ity, signed), valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask), }; - let abi = if tag.value.size(dl) == size { - Abi::Scalar(tag.clone()) - } else { - Abi::Aggregate { sized: true } - }; + let mut abi = Abi::Aggregate { sized: true }; + if tag.value.size(dl) == size { + abi = Abi::Scalar(tag.clone()); + } else if !tag.is_bool() { + // HACK(nox): Blindly using ScalarPair for all tagged enums + // where applicable leads to Option being handled as {i1, i8}, + // which later confuses SROA and some loop optimisations, + // ultimately leading to the repeat-trusted-len test + // failing. We make the trade-off of using ScalarPair only + // for types where the tag isn't a boolean. + let mut common_prim = None; + for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { + let offsets = match layout_variant.fields { + FieldPlacement::Arbitrary { ref offsets, .. } => offsets, + _ => bug!(), + }; + let mut fields = field_layouts + .iter() + .zip(offsets) + .filter(|p| !p.0.is_zst()); + let (field, offset) = match (fields.next(), fields.next()) { + (None, None) => continue, + (Some(pair), None) => pair, + _ => { + common_prim = None; + break; + } + }; + let prim = match field.details.abi { + Abi::Scalar(ref scalar) => scalar.value, + _ => { + common_prim = None; + break; + } + }; + if let Some(pair) = common_prim { + // This is pretty conservative. We could go fancier + // by conflating things like i32 and u32, or even + // realising that (u8, u8) could just cohabit with + // u16 or even u32. + if pair != (prim, offset) { + common_prim = None; + break; + } + } else { + common_prim = Some((prim, offset)); + } + } + if let Some((prim, offset)) = common_prim { + let pair = scalar_pair(tag.clone(), scalar_unit(prim)); + let pair_offsets = match pair.fields { + FieldPlacement::Arbitrary { + ref offsets, + ref memory_index + } => { + assert_eq!(memory_index, &[0, 1]); + offsets + } + _ => bug!() + }; + if pair_offsets[0] == Size::from_bytes(0) && + pair_offsets[1] == *offset && + align == pair.align && + size == pair.size { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; + } + } + } tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { discr: tag, - variants + variants: layout_variants, }, fields: FieldPlacement::Arbitrary { offsets: vec![Size::from_bytes(0)], diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index 155319cb154..f306608f432 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -29,7 +29,6 @@ pub enum Enum4 { A(i32), B(i32), } -// CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } pub enum Enum64 { @@ -59,7 +58,7 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { // CHECK-LABEL: @enum4 #[no_mangle] pub fn enum4(a: i32) -> Enum4 { -// CHECK: %e4 = alloca %Enum4, align 4 +// CHECK: %e4 = alloca { i32, i32 }, align 4 let e4 = Enum4::A(a); e4 } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index de302c69056..40a9ea5a181 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -145,6 +145,18 @@ pub fn return_slice(x: &[u16]) -> &[u16] { x } +// CHECK: { i16, i16 } @enum_id_1(i16 %x.0, i16 %x.1) +#[no_mangle] +pub fn enum_id_1(x: Option>) -> Option> { + x +} + +// CHECK: i16 @enum_id_2(i16) +#[no_mangle] +pub fn enum_id_2(x: Option) -> Option { + x +} + // CHECK: noalias i8* @allocator() #[no_mangle] #[allocator] diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 62aa93398ac..ea3f0de5d08 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -25,16 +25,16 @@ pub fn test() { let b = &Some(a); &b; // keep variable in an alloca -// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* +// CHECK: [[S_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__4:%[0-9]+]] = bitcast %"core::option::Option"* %_4 to i8* +// CHECK: [[S__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* +// CHECK: [[E_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) -// CHECK: [[E__4:%[0-9]+]] = bitcast %"core::option::Option"* %_4 to i8* +// CHECK: [[E__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]]) } -- cgit 1.4.1-3-g733a5 From 90656441a9dfbc42b6f5f1f25abeead66012bb00 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 22 Apr 2018 18:40:54 +0200 Subject: Emit range metadata on calls returning scalars (fixes #50157) --- src/librustc_target/abi/mod.rs | 19 ++++++++++++++++++- src/librustc_target/lib.rs | 1 + src/librustc_trans/abi.rs | 22 ++++++++++++++++++++-- src/librustc_trans/lib.rs | 1 + src/librustc_trans/mir/block.rs | 4 ++-- src/librustc_trans/mir/place.rs | 23 +++++++---------------- src/test/codegen/call-metadata.rs | 29 +++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 src/test/codegen/call-metadata.rs (limited to 'src/test/codegen') diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 18dd04c0ee8..346e5667a7b 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -14,7 +14,7 @@ pub use self::Primitive::*; use spec::Target; use std::cmp; -use std::ops::{Add, Deref, Sub, Mul, AddAssign, RangeInclusive}; +use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; pub mod call; @@ -544,6 +544,23 @@ impl Scalar { false } } + + /// Returns the valid range as a `x..y` range. + /// + /// If `x` and `y` are equal, the range is full, not empty. + pub fn valid_range_exclusive(&self, cx: C) -> Range { + // For a (max) value of -1, max will be `-1 as usize`, which overflows. + // However, that is fine here (it would still represent the full range), + // i.e., if the range is everything. + let bits = self.value.size(cx).bits(); + assert!(bits <= 128); + let mask = !0u128 >> (128 - bits); + let start = self.valid_range.start; + let end = self.valid_range.end; + assert_eq!(start, start & mask); + assert_eq!(end, end & mask); + start..(end.wrapping_add(1) & mask) + } } /// Describes how the fields of a type are located in memory. diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 8f491157439..927d5c7e15a 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -29,6 +29,7 @@ #![feature(const_fn)] #![feature(fs_read_write)] #![feature(inclusive_range)] +#![feature(inclusive_range_fields)] #![feature(slice_patterns)] #[macro_use] diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 483f36afe27..1d0d7ec601f 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -265,7 +265,7 @@ pub trait FnTypeExt<'a, 'tcx> { fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; fn llvm_cconv(&self) -> llvm::CallConv; fn apply_attrs_llfn(&self, llfn: ValueRef); - fn apply_attrs_callsite(&self, callsite: ValueRef); + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef); } impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { @@ -640,7 +640,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { } } - fn apply_attrs_callsite(&self, callsite: ValueRef) { + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); @@ -653,6 +653,24 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Indirect(ref attrs) => apply(attrs), _ => {} } + if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { + // If the value is a boolean, the range is 0..2 and that ultimately + // become 0..0 when the type becomes i1, which would be rejected + // by the LLVM verifier. + match scalar.value { + layout::Int(..) if !scalar.is_bool() => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + // FIXME(nox): This causes very weird type errors about + // SHL operators in constants in stage 2 with LLVM 3.9. + if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { + bx.range_metadata(callsite, range); + } + } + } + _ => {} + } + } for arg in &self.args { if arg.pad.is_some() { apply(&ArgAttributes::new()); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index dab01abd335..96a10e8b99d 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -25,6 +25,7 @@ #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] +#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 36f03605fea..b9e272e993e 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -127,7 +127,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { ret_bx, llblock(this, cleanup), cleanup_bundle); - fn_ty.apply_attrs_callsite(invokeret); + fn_ty.apply_attrs_callsite(&bx, invokeret); if let Some((ret_dest, target)) = destination { let ret_bx = this.build_block(target); @@ -136,7 +136,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } else { let llret = bx.call(fn_ptr, &llargs, cleanup_bundle); - fn_ty.apply_attrs_callsite(llret); + fn_ty.apply_attrs_callsite(&bx, llret); if this.mir[bb].is_cleanup { // Cleanup is always the cold path. Don't inline // drop glue. Also, when there is a deeply-nested diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index b340d91b027..680c7038998 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -91,24 +91,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } let scalar_load_metadata = |load, scalar: &layout::Scalar| { - let (min, max) = (scalar.valid_range.start, scalar.valid_range.end); - let max_next = max.wrapping_add(1); - let bits = scalar.value.size(bx.cx).bits(); - assert!(bits <= 128); - let mask = !0u128 >> (128 - bits); - // For a (max) value of -1, max will be `-1 as usize`, which overflows. - // However, that is fine here (it would still represent the full range), - // i.e., if the range is everything. The lo==hi case would be - // rejected by the LLVM verifier (it would mean either an - // empty set, which is impossible, or the entire range of the - // type, which is pointless). + let vr = scalar.valid_range.clone(); match scalar.value { - layout::Int(..) if max_next & mask != min & mask => { - // llvm::ConstantRange can deal with ranges that wrap around, - // so an overflow on (max + 1) is fine. - bx.range_metadata(load, min..max_next); + layout::Int(..) => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + bx.range_metadata(load, range); + } } - layout::Pointer if 0 < min && min < max => { + layout::Pointer if vr.start < vr.end && !vr.contains(&0) => { bx.nonnull_metadata(load); } _ => {} diff --git a/src/test/codegen/call-metadata.rs b/src/test/codegen/call-metadata.rs new file mode 100644 index 00000000000..20d42ed852d --- /dev/null +++ b/src/test/codegen/call-metadata.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that range metadata gets emitted on calls to functions returning a +// scalar value. + +// compile-flags: -C no-prepopulate-passes +// min-llvm-version 4.0 + + +#![crate_type = "lib"] + +pub fn test() { + // CHECK: call i8 @some_true(), !range [[R0:![0-9]+]] + // CHECK: [[R0]] = !{i8 0, i8 3} + some_true(); +} + +#[no_mangle] +fn some_true() -> Option { + Some(true) +} -- cgit 1.4.1-3-g733a5 From 69ec4aa97c23cfc316ec340d1afcaaeb4877e8ef Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Apr 2018 20:35:26 +0200 Subject: Mark functions returning uninhabited types as noreturn --- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/declare.rs | 4 ++-- src/test/codegen/noreturnflag.rs | 22 ++++++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 193db15303f..30676b91620 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -271,7 +271,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } None => {} }; - if sig.output().is_never() { + if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited { flags = flags | DIFlags::FlagNoReturn; } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index bbe4e18b18c..97721ffbf06 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -23,6 +23,7 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_target::spec::PanicStrategy; use abi::{Abi, FnType, FnTypeExt}; @@ -133,8 +134,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, let fty = FnType::new(cx, sig, &[]); let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); - // FIXME(canndrew): This is_never should really be an is_uninhabited - if sig.output().is_never() { + if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited { llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 24a5a4e44cb..7239223ca20 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -8,17 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -g -C no-prepopulate-passes // ignore-tidy-linelength // min-llvm-version 4.0 -// compile-flags: -g -C no-prepopulate-passes - -// CHECK: {{.*}}DISubprogram{{.*}}name: "foo"{{.*}}DIFlagNoReturn +#![crate_type = "lib"] -fn foo() -> ! { +#[no_mangle] +pub fn foo() -> ! { +// CHECK: @foo() unnamed_addr #0 loop {} } -pub fn main() { - foo(); +pub enum EmptyEnum {} + +#[no_mangle] +pub fn bar() -> EmptyEnum { +// CHECK: @bar() unnamed_addr #0 + loop {} } + +// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} + +// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn +// CHECK: DISubprogram(name: "bar", {{.*}} DIFlagNoReturn -- cgit 1.4.1-3-g733a5 From 622371153c66f9e371f587205d14040534060c18 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 Apr 2018 15:17:07 -0700 Subject: Add `-C target-feature` to all functions Previously the features specified to LLVM via `-C target-feature` were only reflected in the `TargetMachine` but this change *also* reflects these and the base features inside each function itself. This change matches clang and... Closes rust-lang-nursery/stdsimd#427 --- src/librustc_trans/attributes.rs | 30 ++++++++++++++++++------ src/librustc_trans/back/write.rs | 31 ++++--------------------- src/test/codegen/target-feature-on-functions.rs | 19 +++++++++++++++ 3 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 src/test/codegen/target-feature-on-functions.rs (limited to 'src/test/codegen') diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index eb5c7396ae0..f455c19cc0b 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -14,6 +14,7 @@ use std::ffi::{CStr, CString}; use rustc::hir::{self, TransFnAttrFlags}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; @@ -104,6 +105,18 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { cstr("probe-stack\0"), cstr("__rust_probestack\0")); } +pub fn llvm_target_features(sess: &Session) -> impl Iterator { + const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ + "crt-static", + ]; + + let cmdline = sess.opts.cg.target_feature.split(',') + .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); + sess.target.target.options.features.split(',') + .chain(cmdline) + .filter(|l| !l.is_empty()) +} + /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { @@ -131,13 +144,16 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { unwind(llfn, false); } - let features = - trans_fn_attrs.target_features - .iter() - .map(|f| { - let feature = &*f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) - }) + let features = llvm_target_features(cx.tcx.sess) + .map(|s| s.to_string()) + .chain( + trans_fn_attrs.target_features + .iter() + .map(|f| { + let feature = &*f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + }) + ) .collect::>() .join(","); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 613a07cd269..148e3d0025c 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use attributes; use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; use back::lto::{self, ModuleBuffer, ThinBuffer}; use back::link::{self, get_linker, remove}; @@ -111,31 +112,6 @@ pub fn write_output_file( } } -// On android, we by default compile for armv7 processors. This enables -// things like double word CAS instructions (rather than emulating them) -// which are *far* more efficient. This is obviously undesirable in some -// cases, so if any sort of target feature is specified we don't append v7 -// to the feature list. -// -// On iOS only armv7 and newer are supported. So it is useful to -// get all hardware potential via VFP3 (hardware floating point) -// and NEON (SIMD) instructions supported by LLVM. -// Note that without those flags various linking errors might -// arise as some of intrinsics are converted into function calls -// and nobody provides implementations those functions -fn target_feature(sess: &Session) -> String { - let rustc_features = [ - "crt-static", - ]; - let requested_features = sess.opts.cg.target_feature.split(','); - let llvm_features = requested_features.filter(|f| { - !rustc_features.iter().any(|s| f.contains(s)) - }); - format!("{},{}", - sess.target.target.options.features, - llvm_features.collect::>().join(",")) -} - fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { config::OptLevel::No => llvm::CodeGenOptLevel::None, @@ -203,7 +179,10 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) None => &*sess.target.target.options.cpu }; let cpu = CString::new(cpu.as_bytes()).unwrap(); - let features = CString::new(target_feature(sess).as_bytes()).unwrap(); + let features = attributes::llvm_target_features(sess) + .collect::>() + .join(","); + let features = CString::new(features).unwrap(); let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; diff --git a/src/test/codegen/target-feature-on-functions.rs b/src/test/codegen/target-feature-on-functions.rs new file mode 100644 index 00000000000..e3cc2c753e5 --- /dev/null +++ b/src/test/codegen/target-feature-on-functions.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 +// compile-flags: -C target-feature=+avx + +#![crate_type = "lib"] + +#[no_mangle] +pub fn foo() { + // CHECK: attributes #0 = { {{.*}}"target-features"="+avx"{{.*}} } +} -- cgit 1.4.1-3-g733a5 From 5b800c231f45fcd823a3e958bb942cd620ceb3e0 Mon Sep 17 00:00:00 2001 From: Björn Steinbrink Date: Wed, 3 Jan 2018 10:29:27 +0100 Subject: Don't force-enable frame pointers when generating debug info We apparently used to generate bad/incomplete debug info causing debuggers not to find symbols of stack allocated variables. This was somehow worked around by having frame pointers. With the current codegen, this seems no longer necessary, so we can remove the code that force-enables frame pointers whenever debug info is requested. Since certain situations, like profiling code profit from having frame pointers, we add a -Cforce-frame-pointers flag to always enable frame pointers. Fixes #11906 --- src/librustc/session/config.rs | 6 ++++++ src/librustc/session/mod.rs | 2 +- src/librustc_trans/attributes.rs | 2 -- src/test/codegen/force-frame-pointers.rs | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/force-frame-pointers.rs (limited to 'src/test/codegen') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 06922d986b3..023be789222 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1053,6 +1053,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, 2 = full debug info with variable and type information"), opt_level: Option = (None, parse_opt_string, [TRACKED], "optimize with possible levels 0-3, s, or z"), + force_frame_pointers: bool = (false, parse_bool, [TRACKED], + "force frame pointers to be used"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the cfg(debug_assertions) directive"), inline_threshold: Option = (None, parse_opt_uint, [TRACKED], @@ -2965,6 +2967,10 @@ mod tests { opts.cg.debuginfo = Some(0xba5eba11); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); + opts.cg.force_frame_pointers = true; + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + opts = reference.clone(); opts.cg.debug_assertions = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 37a6b2e79f7..45b7e2d1740 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{DebugInfoLevel, OutputType}; +use session::config::{OutputType}; use ty::tls; use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index f455c19cc0b..5baed57092d 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -69,8 +69,6 @@ pub fn naked(val: ValueRef, is_naked: bool) { } pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) { - // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a - // parameter. if cx.sess().must_not_eliminate_frame_pointers() { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, diff --git a/src/test/codegen/force-frame-pointers.rs b/src/test/codegen/force-frame-pointers.rs new file mode 100644 index 00000000000..d40406a0476 --- /dev/null +++ b/src/test/codegen/force-frame-pointers.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// compile-flags: -C no-prepopulate-passes -C force-frame-pointers + +#![crate_type="lib"] + +// CHECK: attributes #{{.*}} "no-frame-pointer-elim"="true" +pub fn foo() {} -- cgit 1.4.1-3-g733a5 From 09d2db4e963c6696f7c22386b6791e419ad75cfb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 6 Mar 2018 20:27:19 +0200 Subject: Rework force-frame-pointer This reworks the force-frame-pointer PR to explicitly only consider the value of the flag if it is provided, and use a target default otherwise. Something that was tried but not kept was renaming the flag to `frame-pointer`, because for flag `frame-pointer=no`, there is no guarante, that LLVM will elide *all* the frame pointers; oposite of what the literal reading of the flag would suggest. --- src/librustc/session/config.rs | 6 +++--- src/librustc/session/mod.rs | 7 +++++-- src/test/codegen/force-frame-pointers.rs | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 023be789222..59b40e9e2dc 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1053,8 +1053,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, 2 = full debug info with variable and type information"), opt_level: Option = (None, parse_opt_string, [TRACKED], "optimize with possible levels 0-3, s, or z"), - force_frame_pointers: bool = (false, parse_bool, [TRACKED], - "force frame pointers to be used"), + force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], + "force use of the frame pointers"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the cfg(debug_assertions) directive"), inline_threshold: Option = (None, parse_opt_uint, [TRACKED], @@ -2968,7 +2968,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.cg.force_frame_pointers = true; + opts.cg.force_frame_pointers = Some(false); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 45b7e2d1740..2ab72ba20bf 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -658,8 +658,11 @@ impl Session { } pub fn must_not_eliminate_frame_pointers(&self) -> bool { - self.opts.debuginfo != DebugInfoLevel::NoDebugInfo - || !self.target.target.options.eliminate_frame_pointer + if let Some(x) = self.opts.cg.force_frame_pointers { + x + } else { + !self.target.target.options.eliminate_frame_pointer + } } /// Returns the symbol name for the registrar function, diff --git a/src/test/codegen/force-frame-pointers.rs b/src/test/codegen/force-frame-pointers.rs index d40406a0476..f70e3667198 100644 --- a/src/test/codegen/force-frame-pointers.rs +++ b/src/test/codegen/force-frame-pointers.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -// compile-flags: -C no-prepopulate-passes -C force-frame-pointers +// compile-flags: -C no-prepopulate-passes -C force-frame-pointers=y #![crate_type="lib"] -- cgit 1.4.1-3-g733a5 From fdd9787777dac5db6bd555df08038e3c191999e4 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 26 Apr 2018 09:18:19 +0200 Subject: Introduce ConstValue and use it instead of miri's Value for constant values --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/ich/impls_ty.rs | 24 +++ src/librustc/middle/const_val.rs | 24 +-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/mir/interpret/mod.rs | 62 ++++++- src/librustc/mir/interpret/value.rs | 64 ++++++- src/librustc/mir/mod.rs | 21 +-- src/librustc/mir/tcx.rs | 2 +- src/librustc/ty/codec.rs | 19 +++ src/librustc/ty/context.rs | 9 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/maps/config.rs | 2 +- src/librustc/ty/maps/mod.rs | 2 +- src/librustc/ty/mod.rs | 42 ++--- src/librustc/ty/relate.rs | 19 +-- src/librustc/ty/sty.rs | 153 +++++++++++++++++ src/librustc/ty/util.rs | 4 +- src/librustc/util/ppaux.rs | 10 +- .../borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 21 +-- src/librustc_mir/build/matches/test.rs | 5 +- src/librustc_mir/build/misc.rs | 7 +- src/librustc_mir/hair/cx/expr.rs | 37 ++-- src/librustc_mir/hair/cx/mod.rs | 45 ++--- src/librustc_mir/hair/pattern/_match.rs | 186 ++++++++++----------- src/librustc_mir/hair/pattern/mod.rs | 137 +++++++-------- src/librustc_mir/interpret/const_eval.rs | 128 +++++++++----- src/librustc_mir/interpret/eval_context.rs | 171 ++++++++++--------- src/librustc_mir/interpret/memory.rs | 69 ++------ src/librustc_mir/interpret/mod.rs | 1 + src/librustc_mir/interpret/place.rs | 16 +- src/librustc_mir/monomorphize/collector.rs | 23 +-- src/librustc_mir/monomorphize/item.rs | 3 +- src/librustc_mir/shim.rs | 21 +-- src/librustc_mir/transform/const_prop.rs | 128 ++++++++------ src/librustc_mir/transform/elaborate_drops.rs | 7 +- src/librustc_mir/transform/generator.rs | 15 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_mir/transform/simplify_branches.rs | 17 +- .../transform/uniform_array_move_out.rs | 8 +- src/librustc_mir/util/elaborate_drops.rs | 13 +- src/librustc_mir/util/pretty.rs | 2 +- src/librustc_trans/base.rs | 18 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/constant.rs | 106 ++++++++---- src/librustc_trans/mir/operand.rs | 32 ++-- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/astconv.rs | 6 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 9 +- src/test/codegen/link_section.rs | 8 +- 55 files changed, 985 insertions(+), 737 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e4f432e7caf..54dda320e1f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,7 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, ConstValue}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d0d0ab093c8..1036eae9b85 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -384,6 +384,30 @@ for ::middle::const_val::ConstVal<'gcx> { } } +impl<'a, 'gcx> HashStable> +for ::mir::interpret::ConstValue<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use mir::interpret::ConstValue::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ByVal(val) => { + val.hash_stable(hcx, hasher); + } + ByValPair(a, b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + ByRef(alloc) => { + alloc.hash_stable(hcx, hasher); + } + } + } +} + impl_stable_hash_for!(enum mir::interpret::Value { ByVal(v), ByValPair(a, b), diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 0ecab50dda2..3a76f75d018 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::ConstValue; use errors::DiagnosticBuilder; use graphviz::IntoCow; @@ -25,27 +25,7 @@ pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { Unevaluated(DefId, &'tcx Substs<'tcx>), - Value(Value), -} - -impl<'tcx> ConstVal<'tcx> { - pub fn to_raw_bits(&self) -> Option { - match *self { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - Some(b) - }, - _ => None, - } - } - pub fn unwrap_u64(&self) -> u64 { - match self.to_raw_bits() { - Some(val) => { - assert_eq!(val as u64 as u128, val); - val as u64 - }, - None => bug!("expected constant u64, got {:#?}", self), - } - } + Value(ConstValue<'tcx>), } #[derive(Clone, Debug)] diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3875770a5ff..a4c38333da1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -945,7 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true, + ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 546c7a920d5..afdd1c167c6 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -10,7 +10,7 @@ mod value; pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; -pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; +pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue}; use std::collections::BTreeMap; use std::fmt; @@ -20,8 +20,10 @@ use ty::{self, TyCtxt}; use ty::layout::{self, Align, HasDataLayout}; use middle::region; use std::iter; +use std::io; use syntax::ast::Mutability; use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; +use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lock { @@ -235,7 +237,7 @@ impl fmt::Display for AllocId { } } -#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer @@ -254,17 +256,69 @@ pub struct Allocation { } impl Allocation { - pub fn from_bytes(slice: &[u8]) -> Self { + pub fn from_bytes(slice: &[u8], align: Align) -> Self { let mut undef_mask = UndefMask::new(0); undef_mask.grow(slice.len() as u64, true); Self { bytes: slice.to_owned(), relocations: BTreeMap::new(), undef_mask, - align: Align::from_bytes(1, 1).unwrap(), + align, runtime_mutability: Mutability::Immutable, } } + + pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self { + Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap()) + } + + pub fn undef(size: u64, align: Align) -> Self { + assert_eq!(size as usize as u64, size); + Allocation { + bytes: vec![0; size as usize], + relocations: BTreeMap::new(), + undef_mask: UndefMask::new(size), + align, + runtime_mutability: Mutability::Immutable, + } + } +} + +impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {} + +//////////////////////////////////////////////////////////////////////////////// +// Methods to access integers in the target endianness +//////////////////////////////////////////////////////////////////////////////// + +pub fn write_target_uint( + endianness: layout::Endian, + mut target: &mut [u8], + data: u128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_uint128::(data, len), + layout::Endian::Big => target.write_uint128::(data, len), + } +} + +pub fn write_target_int( + endianness: layout::Endian, + mut target: &mut [u8], + data: i128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_int128::(data, len), + layout::Endian::Big => target.write_int128::(data, len), + } +} + +pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { + layout::Endian::Little => source.read_uint128::(source.len()), + layout::Endian::Big => source.read_uint128::(source.len()), + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7289d74bfbb..2cd4bf9d18c 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -3,7 +3,69 @@ use ty::layout::{Align, HasDataLayout}; use ty; -use super::{EvalResult, MemoryPointer, PointerArithmetic}; +use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation}; + +/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which +/// matches Value's optimizations for easy conversions between these two types +#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +pub enum ConstValue<'tcx> { + // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef + ByVal(PrimVal), + // Used only for types with layout::abi::ScalarPair + ByValPair(PrimVal, PrimVal), + // Used only for the remaining cases + ByRef(&'tcx Allocation), +} + +impl<'tcx> ConstValue<'tcx> { + #[inline] + pub fn from_byval_value(val: Value) -> Self { + match val { + Value::ByRef(..) => bug!(), + Value::ByValPair(a, b) => ConstValue::ByValPair(a, b), + Value::ByVal(val) => ConstValue::ByVal(val), + } + } + + #[inline] + pub fn to_byval_value(&self) -> Option { + match *self { + ConstValue::ByRef(..) => None, + ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)), + ConstValue::ByVal(val) => Some(Value::ByVal(val)), + } + } + + #[inline] + pub fn from_primval(val: PrimVal) -> Self { + ConstValue::ByVal(val) + } + + #[inline] + pub fn to_primval(&self) -> Option { + match *self { + ConstValue::ByRef(..) => None, + ConstValue::ByValPair(..) => None, + ConstValue::ByVal(val) => Some(val), + } + } + + #[inline] + pub fn to_bits(&self) -> Option { + match self.to_primval() { + Some(PrimVal::Bytes(val)) => Some(val), + _ => None, + } + } + + #[inline] + pub fn to_ptr(&self) -> Option { + match self.to_primval() { + Some(PrimVal::Ptr(ptr)) => Some(ptr), + _ => None, + } + } +} /// A `Value` represents a single self-contained Rust value. /// diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 11e25322f00..eb12444bcb4 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -13,7 +13,6 @@ //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html use graphviz::IntoCow; -use middle::const_val::ConstVal; use middle::region; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -1549,11 +1548,7 @@ impl<'tcx> Operand<'tcx> { span, ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }) + value: ty::Const::zero_sized(tcx, ty), }, }) } @@ -1881,11 +1876,17 @@ impl<'tcx> Debug for Literal<'tcx> { } /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { - use middle::const_val::ConstVal::*; +pub fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { + use middle::const_val::ConstVal; match const_val.val { - Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => print_miri_value(val, const_val.ty, fmt), + ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val), + ConstVal::Value(val) => { + if let Some(value) = val.to_byval_value() { + print_miri_value(value, const_val.ty, fmt) + } else { + write!(fmt, "{:?}:{}", val, const_val.ty) + } + }, } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6a9ff39c5f5..67dfad50f44 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.unwrap_u64(); + let size = size.unwrap_usize(tcx); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 4e15f0711a5..d911f32ed3f 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -24,6 +24,7 @@ use std::hash::Hash; use std::intrinsics; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; +use mir::interpret::Allocation; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) } +#[inline] +pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx Allocation, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) +} + #[macro_export] macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { @@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder { decode_const(self) } } + + impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation> + for $DecoderName<$($typaram),*> { + fn specialized_decode( + &mut self + ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> { + decode_allocation(self) + } + } } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 36eb091cb6e..06e08a0e263 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -26,14 +26,12 @@ use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; -use middle::const_val::ConstVal; use middle::cstore::{CrateStore, LinkMeta}; use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; -use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use ty::Instance; @@ -1132,7 +1130,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return alloc_id; } // create an allocation that just contains these bytes - let alloc = interpret::Allocation::from_bytes(bytes); + let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); let alloc = self.intern_const_alloc(alloc); // the next unique id @@ -2375,10 +2373,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))), - ty: self.types.usize - }))) + self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n))) } pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index cfde35de93c..7dfdc592647 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -182,7 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - match n.val.to_raw_bits() { + match n.assert_usize(tcx) { Some(n) => format!("array of {} elements", n), None => "array".to_string(), } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 17a3d0011ed..19e5406cd0d 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_raw_bits() { + match len.assert_usize(tcx) { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 0688dcabe55..9cbee143990 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.unwrap_u64(); + let count = count.unwrap_usize(tcx); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 57c8c4f34e7..ca594faf5cd 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -11,7 +11,7 @@ use dep_graph::SerializedDepNodeIndex; use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, ConstValue}; use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index d89846a75ef..80402f87650 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -28,7 +28,7 @@ use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; use middle::const_val::EvalResult; use mir::mono::{CodegenUnit, Stats}; use mir; -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, Allocation, ConstValue}; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::{self, Vtable}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7076112e371..eede7bd2ea6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -22,12 +22,11 @@ use hir::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; use infer::canonical::{Canonical, Canonicalize}; -use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits::{self, Reveal}; @@ -1933,27 +1932,23 @@ impl<'a, 'gcx, 'tcx> AdtDef { promoted: None }; match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - ty, - }) => { - trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { - val: b, - ty, - }) - }, - Ok(&ty::Const { - val: ConstVal::Value(other), - .. - }) => { - info!("invalid enum discriminant: {:#?}", other); - ::middle::const_val::struct_error( - tcx, - tcx.def_span(expr_did), - "constant evaluation of enum discriminant resulted in non-integer", - ).emit(); - None + Ok(val) => { + // FIXME: Find the right type and use it instead of `val.ty` here + if let Some(b) = val.assert_bits(val.ty) { + trace!("discriminants: {} ({:?})", b, repr_type); + Some(Discr { + val: b, + ty: val.ty, + }) + } else { + info!("invalid enum discriminant: {:#?}", val); + ::middle::const_val::struct_error( + tcx, + tcx.def_span(expr_did), + "constant evaluation of enum discriminant resulted in non-integer", + ).emit(); + None + } } Err(err) => { err.report(tcx, tcx.def_span(expr_did), "enum discriminant"); @@ -1964,7 +1959,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } None } - _ => span_bug!(tcx.def_span(expr_did), "const eval "), } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 109dfebf154..4a33f1a1f54 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -18,7 +18,7 @@ use middle::const_val::ConstVal; use ty::subst::{Kind, UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -469,8 +469,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, assert_eq!(sz_a.ty, tcx.types.usize); assert_eq!(sz_b.ty, tcx.types.usize); let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { + if let Some(s) = x.assert_usize(tcx) { + return Ok(s); + } match x.val { - ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(); @@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, instance, promoted: None }; - match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - .. - }) => { - assert_eq!(b as u64 as u128, b); - return Ok(b as u64); - } - _ => {} + if let Some(s) = tcx.const_eval(param_env.and(cid)) + .ok() + .map(|c| c.unwrap_usize(tcx)) { + return Ok(s) } } }, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7518f008fb3..f0a7ce54971 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,6 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; use util::captures::Captures; +use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue}; use std::iter; use std::cmp::Ordering; @@ -1730,4 +1731,156 @@ pub struct Const<'tcx> { pub val: ConstVal<'tcx>, } +impl<'tcx> Const<'tcx> { + pub fn unevaluated( + tcx: TyCtxt<'_, '_, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val: ConstVal::Unevaluated(def_id, substs), + ty, + }) + } + + #[inline] + pub fn from_const_val( + tcx: TyCtxt<'_, '_, 'tcx>, + val: ConstVal<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val, + ty, + }) + } + + #[inline] + pub fn from_const_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_val(tcx, ConstVal::Value(val), ty) + } + + #[inline] + pub fn from_alloc( + tcx: TyCtxt<'_, '_, 'tcx>, + alloc: &'tcx Allocation, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty) + } + + #[inline] + pub fn from_byval_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: Value, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty) + } + + #[inline] + pub fn from_primval( + tcx: TyCtxt<'_, '_, 'tcx>, + val: PrimVal, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_primval(val), ty) + } + + #[inline] + pub fn from_bits( + tcx: TyCtxt<'_, '_, 'tcx>, + val: u128, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_primval(tcx, PrimVal::Bytes(val), ty) + } + + #[inline] + pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + Self::from_primval(tcx, PrimVal::Undef, ty) + } + + #[inline] + pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { + Self::from_bits(tcx, v as u128, tcx.types.bool) + } + + #[inline] + pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self { + Self::from_bits(tcx, n as u128, tcx.types.usize) + } + + #[inline] + pub fn to_bits(&self, ty: Ty<'_>) -> Option { + if self.ty != ty { + return None; + } + match self.val { + ConstVal::Value(val) => val.to_bits(), + _ => None, + } + } + + #[inline] + pub fn to_ptr(&self) -> Option { + match self.val { + ConstVal::Value(val) => val.to_ptr(), + _ => None, + } + } + + #[inline] + pub fn to_primval(&self) -> Option { + match self.val { + ConstVal::Value(val) => val.to_primval(), + _ => None, + } + } + + #[inline] + pub fn assert_bits(&self, ty: Ty<'_>) -> Option { + assert_eq!(self.ty, ty); + match self.val { + ConstVal::Value(val) => val.to_bits(), + _ => None, + } + } + + #[inline] + pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx.types.bool).and_then(|v| match v { + 0 => Some(false), + 1 => Some(true), + _ => None, + }) + } + + #[inline] + pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx.types.usize).map(|v| v as u64) + } + + #[inline] + pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 { + match self.assert_bits(ty) { + Some(val) => val, + None => bug!("expected bits of {}, got {:#?}", ty, self), + } + } + + #[inline] + pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 { + match self.assert_usize(tcx) { + Some(val) => val, + None => bug!("expected constant usize, got {:#?}", self), + } + } +} + impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 80dc3b2b452..76803f45031 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -25,7 +25,6 @@ use ty::TypeVariants::*; use ty::layout::{Integer, IntegerExt}; use util::common::ErrorReported; use middle::lang_items; -use mir::interpret::{Value, PrimVal}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; @@ -659,9 +658,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyArray(_, n) => { self.hash_discriminant_u8(&n.val); match n.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), + ConstVal::Value(alloc) => self.hash(alloc), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), - _ => bug!("arrays should not have {:?} as length", n) } } TyRawPtr(m) => self.hash(m.mutbl), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4fb10170351..a6eb468e338 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,7 +21,6 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; -use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -1183,15 +1182,12 @@ define_print! { TyArray(ty, sz) => { print!(f, cx, write("["), print(ty), write("; "))?; match sz.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { - write!(f, "{}", sz)?; - } + ConstVal::Value(..) => ty::tls::with(|tcx| { + write!(f, "{}", sz.unwrap_usize(tcx)) + })?, ConstVal::Unevaluated(_def_id, _substs) => { write!(f, "_")?; } - _ => { - write!(f, "{:?}", sz)?; - } } write!(f, "]") } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 42a1745addf..1014299c708 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -425,7 +425,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let size = size.val.unwrap_u64(); + let size = size.unwrap_usize(tcx); let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 648746b6e90..20e11abca9f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -16,11 +16,10 @@ use rustc_data_structures::indexed_vec::Idx; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use hair::*; -use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty, UpvarSubsts}; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind}; +use rustc::mir::interpret::EvalErrorKind; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -200,10 +199,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: expr_span, ty: this.hir.tcx().types.u32, literal: Literal::Value { - value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: this.hir.tcx().types.u32 - }), + value: ty::Const::from_bits( + this.hir.tcx(), + 0, + this.hir.tcx().types.u32), }, })); box AggregateKind::Generator(closure_id, substs, movability) @@ -378,10 +377,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bits = self.hir.integer_bit_width(ty); let n = (!0u128) >> (128 - bits); let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), n, ty) }; self.literal_operand(span, ty, literal) @@ -393,10 +389,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bits = self.hir.integer_bit_width(ty); let n = 1 << (bits - 1); let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), n, ty) }; self.literal_operand(span, ty, literal) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index d6ddfea1f19..913cb944835 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -122,12 +122,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match *match_pair.pattern.kind { PatternKind::Constant { value } => { - // if the places match, the type should match - assert_eq!(match_pair.pattern.ty, switch_ty); - indices.entry(value) .or_insert_with(|| { - options.push(value.val.to_raw_bits().expect("switching on int")); + options.push(value.unwrap_bits(switch_ty)); options.len() - 1 }); true diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 6e10c2307c8..6501dd00fe8 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -13,9 +13,7 @@ use build::Builder; -use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax_pos::{Span, DUMMY_SP}; @@ -64,10 +62,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), 0, ty) }; self.literal_operand(span, ty, literal) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 76605a7aa04..e3ff67703bd 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -14,8 +14,7 @@ use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; -use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::mir::interpret::GlobalId; use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; @@ -522,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, promoted: None }; let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) { - Ok(cv) => cv.val.unwrap_u64(), + Ok(cv) => cv.unwrap_usize(cx.tcx), Err(e) => { e.report(cx.tcx, cx.tcx.def_span(def_id), "array length"); 0 @@ -635,22 +634,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx().mk_const(ty::Const { - val, - ty, - }), + value: val, }, }, }.to_ref(); - let offset = mk_const( - ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))), - ); + let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty)); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ConstVal::Unevaluated(did, substs)); + let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty)); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -707,10 +701,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }), + value: ty::Const::zero_sized(cx.tcx(), ty), }, }, } @@ -764,20 +755,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: cx.tables().node_id_to_type(expr.hir_id) - }), + value: ty::Const::zero_sized( + cx.tcx, + cx.tables().node_id_to_type(expr.hir_id)), }, }, Def::Const(def_id) | Def::AssociatedConst(def_id) => ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(def_id, substs), - ty: cx.tables().node_id_to_type(expr.hir_id) - }), + value: ty::Const::unevaluated( + cx.tcx, + def_id, + substs, + cx.tables().node_id_to_type(expr.hir_id)) }, }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 5890ea5c9d0..4765a82d85b 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,6 @@ use hair::*; -use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -31,7 +30,6 @@ use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; use rustc_data_structures::sync::Lrc; -use rustc::mir::interpret::{Value, PrimVal}; use hair::pattern::parse_float; #[derive(Clone)] @@ -117,10 +115,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> { Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))), - ty: self.tcx.types.usize - }) + value: ty::Const::from_usize(self.tcx, value), } } @@ -134,19 +129,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, true), } } pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, false), } } @@ -162,6 +151,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { layout::Integer::from_attr(self.tcx, ty).size().bits() } + // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const pub fn const_eval_literal( &mut self, lit: &'tcx ast::LitKind, @@ -171,7 +161,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ) -> Literal<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); - let parse_float = |num, fty| -> Value { + let parse_float = |num, fty| -> ConstValue<'tcx> { parse_float(num, fty, neg).unwrap_or_else(|_| { // FIXME(#31407) this is only necessary because float parsing is buggy self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); @@ -193,7 +183,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let s = s.as_str(); let id = self.tcx.allocate_cached(s.as_bytes()); let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( + ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), ) @@ -201,16 +191,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { LitKind::ByteStr(ref data) => { let id = self.tcx.allocate_cached(data); let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) + ConstValue::ByVal(PrimVal::Ptr(ptr)) }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), LitKind::Int(n, _) if neg => { let n = n as i128; let n = n.overflowing_neg().0; let n = clamp(n as u128); - Value::ByVal(PrimVal::Bytes(n)) + ConstValue::ByVal(PrimVal::Bytes(n)) }, - LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))), + LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))), LitKind::Float(n, fty) => { parse_float(n, fty) } @@ -221,14 +211,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { }; parse_float(n, fty) } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)), }; Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(lit), - ty, - }), + value: ty::Const::from_const_value(self.tcx, lit, ty) } } @@ -258,11 +245,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Value { - value: self.tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: method_ty - }), + value: ty::Const::zero_sized(self.tcx, method_ty) }); } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 1245f506955..f930d47dc0b 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -25,7 +25,6 @@ use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::Field; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::common::ErrorReported; use syntax_pos::{Span, DUMMY_SP}; @@ -180,37 +179,34 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { self.byte_array_map.entry(pat).or_insert_with(|| { match pat.kind { box PatternKind::Constant { - value: &ty::Const { val: ConstVal::Value(b), ty } + value: const_val } => { - match b { - Value::ByVal(PrimVal::Ptr(ptr)) => { - let is_array_ptr = ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == tcx.types.u8); - assert!(is_array_ptr); - let alloc = tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .unwrap(); - assert_eq!(ptr.offset, 0); - // FIXME: check length - alloc.bytes.iter().map(|b| { - &*pattern_arena.alloc(Pattern { - ty: tcx.types.u8, - span: pat.span, - kind: box PatternKind::Constant { - value: tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal( - PrimVal::Bytes(*b as u128), - )), - ty: tcx.types.u8 - }) - } - }) - }).collect() - }, - _ => bug!("not a byte str: {:?}", b), + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .unwrap(); + assert_eq!(ptr.offset, 0); + // FIXME: check length + alloc.bytes.iter().map(|b| { + &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: ty::Const::from_bits( + tcx, + *b as u128, + tcx.types.u8) + } + }) + }).collect() + } else { + bug!("not a byte str: {:?}", const_val) } } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) @@ -439,14 +435,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match pcx.ty.sty { ty::TyBool => { [true, false].iter().map(|&b| { - ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))), - ty: cx.tcx.types.bool - })) + ConstantValue(ty::Const::from_bool(cx.tcx, b)) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => { - let len = len.val.unwrap_u64(); + ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => { + let len = len.unwrap_usize(cx.tcx); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( for row in patterns { match *row.kind { PatternKind::Constant { - value: &ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), - ty, + value: const_val @ &ty::Const { + val: ConstVal::Value(..), + .. } } => { - let is_array_ptr = ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == cx.tcx.types.u8); - if is_array_ptr { - let alloc = cx.tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .unwrap(); - max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + if is_array_ptr { + let alloc = cx.tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } } } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { @@ -836,7 +831,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. /// /// Returns None in case of a catch-all, which can't be specialized. -fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, +fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt, pat: &Pattern<'tcx>, pcx: PatternContext) -> Option>> @@ -854,7 +849,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { ty::TyArray(_, length) => Some(vec![ - Slice(length.val.unwrap_u64()) + Slice(length.unwrap_usize(cx.tcx)) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -934,27 +929,31 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, - ctor: &Constructor, - prefix: &[Pattern], - slice: &Option, - suffix: &[Pattern]) - -> Result { +fn slice_pat_covered_by_constructor<'tcx>( + tcx: TyCtxt<'_, 'tcx, '_>, + _span: Span, + ctor: &Constructor, + prefix: &[Pattern<'tcx>], + slice: &Option>, + suffix: &[Pattern<'tcx>] +) -> Result { let data: &[u8] = match *ctor { - ConstantValue(&ty::Const { val: ConstVal::Value( - Value::ByVal(PrimVal::Ptr(ptr)) - ), ty }) => { - let is_array_ptr = ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == tcx.types.u8); - assert!(is_array_ptr); - tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .unwrap() - .bytes - .as_ref() + ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => { + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .unwrap() + .bytes + .as_ref() + } else { + bug!() + } } _ => bug!() }; @@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, data[data.len()-suffix.len()..].iter().zip(suffix)) { match pat.kind { - box PatternKind::Constant { value } => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - assert_eq!(b as u8 as u128, b); - if b as u8 != *ch { - return Ok(false); - } + box PatternKind::Constant { value } => { + let b = value.unwrap_bits(pat.ty); + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); } - _ => span_bug!(pat.span, "bad const u8 {:?}", value) - }, + } _ => {} } } @@ -987,8 +984,8 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, fn constructor_covered_by_range<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - ctor: &Constructor, - from: &ConstVal, to: &ConstVal, + ctor: &Constructor<'tcx>, + from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>, end: RangeEnd, ty: Ty<'tcx>, ) -> Result { @@ -1006,22 +1003,22 @@ fn constructor_covered_by_range<'a, 'tcx>( } match *ctor { ConstantValue(value) => { - let to = some_or_ok!(cmp_to(&value.val)); + let to = some_or_ok!(cmp_to(value)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&value.val)) && end) + Ok(some_or_ok!(cmp_from(value)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = some_or_ok!(cmp_to(&to.val)); + let to = some_or_ok!(cmp_to(to)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&from.val)) && end) + Ok(some_or_ok!(cmp_from(from)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = some_or_ok!(cmp_to(&to.val)); + let to = some_or_ok!(cmp_to(to)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&from.val)) && end) + Ok(some_or_ok!(cmp_from(from)) && end) } Single => Ok(true), _ => bug!(), @@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Constant { value } => { match *constructor { - Slice(..) => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + Slice(..) => { + if let Some(ptr) = value.to_ptr() { let is_array_ptr = value.ty .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) @@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } else { None } - } - _ => span_bug!(pat.span, + } else { + span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) + } }, _ => { match constructor_covered_by_range( cx.tcx, - constructor, &value.val, &value.val, RangeEnd::Included, + constructor, value, value, RangeEnd::Included, value.ty, ) { Ok(true) => Some(vec![]), @@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( cx.tcx, - constructor, &lo.val, &hi.val, end.clone(), lo.ty, + constructor, lo, hi, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 2585447fa0a..749e574ff7a 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -19,8 +19,8 @@ pub(crate) use self::check_match::check_match; use interpret::{const_val_field, const_variant_index, self}; use rustc::middle::const_val::ConstVal; -use rustc::mir::{Field, BorrowKind, Mutability}; -use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -124,24 +124,11 @@ pub enum PatternKind<'tcx> { fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { match value.val { - ConstVal::Value(v) => print_miri_value(v, value.ty, f), + ConstVal::Value(..) => fmt_const_val(f, value), ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } -fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { - use rustc::ty::TypeVariants::*; - match (value, &ty.sty) { - (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), - (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), - (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), - (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), - (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => - write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), - _ => bug!("{:?}: {} not printable in a pattern", value, ty), - } -} - impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -372,7 +359,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; - match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) { + match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) { (RangeEnd::Excluded, Ordering::Less) => PatternKind::Range { lo, hi, end }, (RangeEnd::Excluded, _) => { @@ -616,7 +603,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.unwrap_u64(); + let len = len.unwrap_usize(self.tcx); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -740,8 +727,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tables.local_id_root.expect("literal outside any scope"), self.substs, ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, Err(()) => { self.errors.push(PatternError::FloatBug); @@ -762,8 +748,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tables.local_id_root.expect("literal outside any scope"), self.substs, ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, Err(()) => { self.errors.push(PatternError::FloatBug); @@ -866,7 +851,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } ty::TyArray(_, n) => { PatternKind::Array { - prefix: (0..n.val.unwrap_u64()) + prefix: (0..n.unwrap_usize(self.tcx)) .map(|i| adt_subpattern(i as usize, None)) .collect(), slice: None, @@ -1049,45 +1034,48 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { pub fn compare_const_vals<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - a: &ConstVal, - b: &ConstVal, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, ty: Ty<'tcx>, ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); - use rustc::mir::interpret::{Value, PrimVal}; - match (a, b) { - (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), - &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { - use ::rustc_apfloat::Float; - match ty.sty { - ty::TyFloat(ast::FloatTy::F32) => { - let l = ::rustc_apfloat::ieee::Single::from_bits(a); - let r = ::rustc_apfloat::ieee::Single::from_bits(b); - l.partial_cmp(&r) - }, - ty::TyFloat(ast::FloatTy::F64) => { - let l = ::rustc_apfloat::ieee::Double::from_bits(a); - let r = ::rustc_apfloat::ieee::Double::from_bits(b); - l.partial_cmp(&r) - }, - ty::TyInt(_) => { - let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); - let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); - Some((a as i128).cmp(&(b as i128))) - }, - _ => Some(a.cmp(&b)), - } - }, - _ if a == b => Some(Ordering::Equal), - _ => None, + // FIXME: This should use assert_bits(ty) instead of use_bits + // but triggers possibly bugs due to mismatching of arrays and slices + if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) { + use ::rustc_apfloat::Float; + match ty.sty { + ty::TyFloat(ast::FloatTy::F32) => { + let l = ::rustc_apfloat::ieee::Single::from_bits(a); + let r = ::rustc_apfloat::ieee::Single::from_bits(b); + l.partial_cmp(&r) + }, + ty::TyFloat(ast::FloatTy::F64) => { + let l = ::rustc_apfloat::ieee::Double::from_bits(a); + let r = ::rustc_apfloat::ieee::Double::from_bits(b); + l.partial_cmp(&r) + }, + ty::TyInt(_) => { + let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); + let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); + Some((a as i128).cmp(&(b as i128))) + }, + _ => Some(a.cmp(&b)), + } + } else { + if a == b { + Some(Ordering::Equal) + } else { + None + } } } +// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, neg: bool) - -> Result, ()> { + -> Result<&'tcx ty::Const<'tcx>, ()> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1096,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, let s = s.as_str(); let id = tcx.allocate_cached(s.as_bytes()); let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( + ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), ) @@ -1104,9 +1092,9 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, LitKind::ByteStr(ref data) => { let id = tcx.allocate_cached(data); let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) + ConstValue::ByVal(PrimVal::Ptr(ptr)) }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), LitKind::Int(n, _) => { enum Int { Signed(IntTy), @@ -1119,31 +1107,28 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, ty::TyUint(other) => Int::Unsigned(other), _ => bug!(), }; + // This converts from LitKind::Int (which is sign extended) to + // PrimVal::Bytes (which is zero extended) let n = match ty { // FIXME(oli-obk): are these casts correct? Int::Signed(IntTy::I8) if neg => - (n as i128 as i8).overflowing_neg().0 as i128 as u128, + (n as i8).overflowing_neg().0 as u8 as u128, Int::Signed(IntTy::I16) if neg => - (n as i128 as i16).overflowing_neg().0 as i128 as u128, + (n as i16).overflowing_neg().0 as u16 as u128, Int::Signed(IntTy::I32) if neg => - (n as i128 as i32).overflowing_neg().0 as i128 as u128, + (n as i32).overflowing_neg().0 as u32 as u128, Int::Signed(IntTy::I64) if neg => - (n as i128 as i64).overflowing_neg().0 as i128 as u128, + (n as i64).overflowing_neg().0 as u64 as u128, Int::Signed(IntTy::I128) if neg => (n as i128).overflowing_neg().0 as u128, - Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, - Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, - Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, - Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, - Int::Signed(IntTy::I128) => n, - Int::Unsigned(UintTy::U8) => n as u8 as u128, - Int::Unsigned(UintTy::U16) => n as u16 as u128, - Int::Unsigned(UintTy::U32) => n as u32 as u128, - Int::Unsigned(UintTy::U64) => n as u64 as u128, - Int::Unsigned(UintTy::U128) => n, + Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128, + Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128, + Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128, + Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128, + Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n, _ => bug!(), }; - Value::ByVal(PrimVal::Bytes(n)) + ConstValue::ByVal(PrimVal::Bytes(n)) }, LitKind::Float(n, fty) => { parse_float(n, fty, neg)? @@ -1155,17 +1140,17 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }; parse_float(n, fty, neg)? } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)), }; - Ok(ConstVal::Value(lit)) + Ok(ty::Const::from_const_value(tcx, lit, ty)) } -pub fn parse_float( +pub fn parse_float<'tcx>( num: Symbol, fty: ast::FloatTy, neg: bool, -) -> Result { +) -> Result, ()> { let num = num.as_str(); use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::Float; @@ -1192,5 +1177,5 @@ pub fn parse_float( } }; - Ok(Value::ByVal(PrimVal::Bytes(bits))) + Ok(ConstValue::ByVal(PrimVal::Bytes(bits))) } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index dff9fa271ab..b8bb58b9ed2 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,5 +1,5 @@ use rustc::hir; -use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError}; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; @@ -9,7 +9,10 @@ use rustc::ty::subst::Subst; use syntax::ast::Mutability; use syntax::codemap::Span; -use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId}; +use rustc::mir::interpret::{ + EvalResult, EvalError, EvalErrorKind, GlobalId, + Value, Pointer, PrimVal, AllocId, Allocation, ConstValue, +}; use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; use std::fmt; @@ -57,19 +60,21 @@ pub fn mk_eval_cx<'a, 'tcx>( } pub fn eval_promoted<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, cid: GlobalId<'tcx>, mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); - match res { - Ok(val) => Some(val), - Err(mut err) => { - ecx.report(&mut err, false, None); - None + ecx.with_fresh_body(|ecx| { + let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env); + match res { + Ok(val) => Some(val), + Err(mut err) => { + ecx.report(&mut err, false, None); + None + } } - } + }) } pub fn eval_body<'a, 'tcx>( @@ -87,19 +92,76 @@ pub fn eval_body<'a, 'tcx>( } } +pub fn value_to_const_value<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + val: Value, + ty: Ty<'tcx>, +) -> &'tcx ty::Const<'tcx> { + let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); + + if layout.is_zst() { + return ty::Const::from_const_value( + tcx, + ConstValue::ByVal(PrimVal::Undef), + ty); + } + + let val = match layout.abi { + layout::Abi::Scalar(..) => { + if let Value::ByVal(val) = val { + ConstValue::ByVal(val) + } else { + bug!("expected ByVal value, got {:?}", val); + } + } + layout::Abi::ScalarPair(..) => { + if let Value::ByValPair(a, b) = val { + ConstValue::ByValPair(a, b) + } else { + bug!("expected ByValPair value, got {:?}", val); + } + } + _ => { + if let Value::ByRef(ptr, align) = val { + let ptr = ptr.primval.to_ptr().unwrap(); + assert_eq!(ptr.offset, 0); + let alloc = tcx.interpret_interner + .get_alloc(ptr.alloc_id) + .expect("miri allocation never successfully created"); + assert_eq!(align, alloc.align); + ConstValue::ByRef(alloc) + } else { + bug!("expected ByRef value, got {:?}", val); + } + }, + }; + ty::Const::from_const_value(tcx, val, ty) +} + fn eval_body_and_ecx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { - debug!("eval_body: {:?}, {:?}", cid, param_env); + debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env); // we start out with the best span we have // and try improving it down the road when more information is available let span = tcx.def_span(cid.instance.def_id()); - let mut span = mir.map(|mir| mir.span).unwrap_or(span); + let span = mir.map(|mir| mir.span).unwrap_or(span); let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); - let res = (|| { + let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env); + (r, ecx) +} + +fn eval_body_using_ecx<'a, 'mir, 'tcx>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, + cid: GlobalId<'tcx>, + mir: Option<&'mir mir::Mir<'tcx>>, + param_env: ty::ParamEnv<'tcx>, +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { + debug!("eval_body: {:?}, {:?}", cid, param_env); + let tcx = ecx.tcx.tcx; let mut mir = match mir { Some(mir) => mir, None => ecx.load_mir(cid.instance.def)?, @@ -107,7 +169,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } - span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( @@ -139,14 +200,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( let ptr = ptr.into(); // always try to read the value and report errors let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { - // if it's a constant (so it needs no address, directly compute its value) - Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val, + Some(val) => val, // point at the allocation _ => Value::ByRef(ptr, layout.align), }; Ok((value, ptr, layout.ty)) - })(); - (res, ecx) } pub struct CompileTimeEvaluator; @@ -357,14 +415,16 @@ pub fn const_val_field<'a, 'tcx>( instance: ty::Instance<'tcx>, variant: Option, field: mir::Field, - value: Value, + value: ConstValue<'tcx>, ty: Ty<'tcx>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let result = (|| { + let value = ecx.const_value_to_value(value, ty)?; let (mut field, ty) = match value { - Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), + Value::ByValPair(..) | Value::ByVal(_) => + ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), Value::ByRef(ptr, align) => { let place = Place::Ptr { ptr, @@ -385,10 +445,7 @@ pub fn const_val_field<'a, 'tcx>( Ok((field, ty)) })(); match result { - Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(field), - ty, - })), + Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)), Err(err) => { let (trace, span) = ecx.generate_stacktrace(None); let err = ErrKind::Miri(err, trace); @@ -404,11 +461,12 @@ pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, - value: Value, + val: ConstValue<'tcx>, ty: Ty<'tcx>, ) -> EvalResult<'tcx, usize> { - trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty); + trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); + let value = ecx.const_value_to_value(val, ty)?; let (ptr, align) = match value { Value::ByValPair(..) | Value::ByVal(_) => { let layout = ecx.layout_of(ty)?; @@ -432,17 +490,6 @@ pub fn const_eval_provider<'a, 'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); - if tcx.is_foreign_item(def_id) { - let id = tcx.interpret_interner.cache_static(def_id); - let ty = tcx.type_of(def_id); - let layout = tcx.layout_of(key.param_env.and(ty)).unwrap(); - let ptr = MemoryPointer::new(id, 0); - return Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)), - ty, - })) - } - if let Some(id) = tcx.hir.as_local_node_id(def_id) { let tables = tcx.typeck_tables_of(def_id); let span = tcx.def_span(def_id); @@ -469,11 +516,8 @@ pub fn const_eval_provider<'a, 'tcx>( }; let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.map(|(miri_value, _, miri_ty)| { - tcx.mk_const(ty::Const { - val: ConstVal::Value(miri_value), - ty: miri_ty, - }) + res.map(|(val, _, miri_ty)| { + value_to_const_value(tcx, val, miri_ty) }).map_err(|mut err| { if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3d670acf98c..03137619eda 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -15,7 +15,7 @@ use syntax::codemap::{self, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, - EvalError, EvalResult, EvalErrorKind, MemoryPointer, + EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue, }; use std::mem; @@ -116,15 +116,6 @@ pub struct ValTy<'tcx> { pub ty: Ty<'tcx>, } -impl<'tcx> ValTy<'tcx> { - pub fn from(val: &ty::Const<'tcx>) -> Option { - match val.val { - ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }), - ConstVal::Unevaluated { .. } => None, - } - } -} - impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { type Target = Value; fn deref(&self) -> &Value { @@ -183,6 +174,8 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf } } +const MAX_TERMINATORS: usize = 1_000_000; + impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, @@ -197,10 +190,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M memory: Memory::new(tcx, memory_data), stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit, - terminators_remaining: 1_000_000, + terminators_remaining: MAX_TERMINATORS, } } + pub(crate) fn with_fresh_body R, R>(&mut self, f: F) -> R { + let stack = mem::replace(&mut self.stack, Vec::new()); + let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS); + let r = f(self); + self.stack = stack; + self.terminators_remaining = terminators_remaining; + r + } + pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> { let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "cannot alloc memory for unsized type"); @@ -235,7 +237,27 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M )) } - pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub fn const_value_to_value( + &mut self, + val: ConstValue<'tcx>, + _ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Value> { + match val { + ConstValue::ByRef(alloc) => { + // FIXME: Allocate new AllocId for all constants inside + let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?; + Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align)) + }, + ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)), + ConstValue::ByVal(val) => Ok(Value::ByVal(val)), + } + } + + pub(super) fn const_to_value( + &mut self, + const_val: &ConstVal<'tcx>, + ty: Ty<'tcx> + ) -> EvalResult<'tcx, Value> { match *const_val { ConstVal::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; @@ -244,7 +266,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M promoted: None, }, ty) } - ConstVal::Value(val) => Ok(val), + ConstVal::Value(val) => self.const_value_to_value(val, ty) } } @@ -568,7 +590,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), + ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -592,7 +614,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M // FIXME(CTFE): don't allow computing the length of arrays in const eval let src = self.eval_place(place)?; let ty = self.place_ty(place); - let (_, len) = src.elem_ty_and_len(ty); + let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx); self.write_primval( dest, PrimVal::from_u128(len as u128), @@ -822,8 +844,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Literal::Value { ref value } => self.const_to_value(&value.val, ty)?, Literal::Promoted { index } => { + let instance = self.frame().instance; self.read_global_as_value(GlobalId { - instance: self.frame().instance, + instance, promoted: Some(index), }, ty)? } @@ -997,7 +1020,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } - pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { if self.tcx.is_static(gid.instance.def_id()).is_some() { let alloc_id = self .tcx @@ -1341,92 +1364,84 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } - pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - use syntax::ast::FloatTy; - - let layout = self.layout_of(ty)?; - self.memory.check_align(ptr, ptr_align)?; - - if layout.size.bytes() == 0 { - return Ok(Some(Value::ByVal(PrimVal::Undef))); - } - - let ptr = ptr.to_ptr()?; - let val = match ty.sty { + pub fn validate_ptr_target( + &self, + ptr: MemoryPointer, + ptr_align: Align, + ty: Ty<'tcx> + ) -> EvalResult<'tcx> { + match ty.sty { ty::TyBool => { let val = self.memory.read_primval(ptr, ptr_align, 1)?; - let val = match val { - PrimVal::Bytes(0) => false, - PrimVal::Bytes(1) => true, + match val { + PrimVal::Bytes(0) | PrimVal::Bytes(1) => (), // TODO: This seems a little overeager, should reading at bool type already be insta-UB? _ => return err!(InvalidBool), - }; - PrimVal::from_bool(val) + } } ty::TyChar => { let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32; match ::std::char::from_u32(c) { - Some(ch) => PrimVal::from_char(ch), + Some(..) => (), None => return err!(InvalidChar(c as u128)), } } - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Isize => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, ptr_align, size)? - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Usize => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, ptr_align, size)? - } - - ty::TyFloat(FloatTy::F32) => { - PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?) - } - ty::TyFloat(FloatTy::F64) => { - PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?) - } - - ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?, + ty::TyFnPtr(_) => { + self.memory.read_ptr_sized(ptr, ptr_align)?; + }, ty::TyRef(_, rty, _) | ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => { - return self.read_ptr(ptr, ptr_align, rty).map(Some) + self.read_ptr(ptr, ptr_align, rty)?; } ty::TyAdt(def, _) => { if def.is_box() { - return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some); + self.read_ptr(ptr, ptr_align, ty.boxed_ty())?; + return Ok(()); } if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi { let size = scalar.value.size(self).bytes(); - self.memory.read_primval(ptr, ptr_align, size)? - } else { - return Ok(None); + self.memory.read_primval(ptr, ptr_align, size)?; } } - _ => return Ok(None), - }; + _ => (), + } + Ok(()) + } + + pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { + let layout = self.layout_of(ty)?; + self.memory.check_align(ptr, ptr_align)?; - Ok(Some(Value::ByVal(val))) + if layout.size.bytes() == 0 { + return Ok(Some(Value::ByVal(PrimVal::Undef))); + } + + let ptr = ptr.to_ptr()?; + + // Not the right place to do this + //self.validate_ptr_target(ptr, ptr_align, ty)?; + + match layout.abi { + layout::Abi::Scalar(..) => { + let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?; + Ok(Some(Value::ByVal(primval))) + } + layout::Abi::ScalarPair(ref a, ref b) => { + let (a, b) = (&a.value, &b.value); + let (a_size, b_size) = (a.size(self), b.size(self)); + let a_ptr = ptr; + let b_offset = a_size.abi_align(b.align(self)); + let b_ptr = ptr.offset(b_offset.bytes(), self)?.into(); + let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?; + let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?; + Ok(Some(Value::ByValPair(a_val, b_val))) + } + _ => Ok(None), + } } pub fn frame(&self) -> &Frame<'mir, 'tcx> { @@ -1466,7 +1481,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let ptr = self.into_ptr(src)?; // u64 cast is from usize to u64, which is always good let valty = ValTy { - value: ptr.to_value_with_len(length.val.unwrap_u64() ), + value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 7f8205b8327..18cd75ae0bb 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,6 +1,5 @@ -use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; -use std::collections::{btree_map, BTreeMap, VecDeque}; -use std::{ptr, io}; +use std::collections::{btree_map, VecDeque}; +use std::ptr; use rustc::ty::Instance; use rustc::ty::maps::TyCtxtAt; @@ -8,8 +7,9 @@ use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; -use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer, +use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer, EvalResult, PrimVal, EvalErrorKind}; +pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint}; use super::{EvalContext, Machine}; @@ -79,20 +79,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } /// kind is `None` for statics - pub fn allocate( + pub fn allocate_value( &mut self, - size: u64, - align: Align, + alloc: Allocation, kind: Option>, - ) -> EvalResult<'tcx, MemoryPointer> { - assert_eq!(size as usize as u64, size); - let alloc = Allocation { - bytes: vec![0; size as usize], - relocations: BTreeMap::new(), - undef_mask: UndefMask::new(size), - align, - runtime_mutability: Mutability::Immutable, - }; + ) -> EvalResult<'tcx, AllocId> { let id = self.tcx.interpret_interner.reserve(); M::add_lock(self, id); match kind { @@ -105,6 +96,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.uninitialized_statics.insert(id, alloc); }, } + Ok(id) + } + + /// kind is `None` for statics + pub fn allocate( + &mut self, + size: u64, + align: Align, + kind: Option>, + ) -> EvalResult<'tcx, MemoryPointer> { + let id = self.allocate_value(Allocation::undef(size, align), kind)?; Ok(MemoryPointer::new(id, 0)) } @@ -873,41 +875,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } } -//////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianness -//////////////////////////////////////////////////////////////////////////////// - -pub fn write_target_uint( - endianness: layout::Endian, - mut target: &mut [u8], - data: u128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianness { - layout::Endian::Little => target.write_uint128::(data, len), - layout::Endian::Big => target.write_uint128::(data, len), - } -} - -pub fn write_target_int( - endianness: layout::Endian, - mut target: &mut [u8], - data: i128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianness { - layout::Endian::Little => target.write_int128::(data, len), - layout::Endian::Big => target.write_int128::(data, len), - } -} - -pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { - match endianness { - layout::Endian::Little => source.read_uint128::(source.len()), - layout::Endian::Big => source.read_uint128::(source.len()), - } -} - //////////////////////////////////////////////////////////////////////////////// // Unaligned accesses //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 1eb131810bd..7f9e67a62cc 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -26,6 +26,7 @@ pub use self::const_eval::{ const_eval_provider, const_val_field, const_variant_index, + value_to_const_value, }; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index b5a06286e4e..883b17b8584 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; @@ -69,9 +69,13 @@ impl<'tcx> Place { self.to_ptr_align().0.to_ptr() } - pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { + pub(super) fn elem_ty_and_len( + self, + ty: Ty<'tcx>, + tcx: TyCtxt<'_, 'tcx, '_> + ) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), + ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)), ty::TySlice(elem) => { match self { @@ -320,7 +324,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, len) = base.elem_ty_and_len(outer_ty); + let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!( n < len, @@ -396,7 +400,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!(n >= min_length as u64); @@ -415,7 +419,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!(u64::from(from) <= n - u64::from(to)); let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e051b848c01..e690e8ee880 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -194,7 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer}; +use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt}; @@ -203,7 +203,7 @@ use rustc::session::config; use rustc::mir::{self, Location, Promoted}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::MonoItem; -use rustc::mir::interpret::GlobalId; +use rustc::mir::interpret::{PrimVal, GlobalId}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -1237,22 +1237,17 @@ fn collect_const<'a, 'tcx>( }; match val { ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"), - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { + ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { collect_miri(tcx, a.alloc_id, output); collect_miri(tcx, b.alloc_id, output); } - ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) | - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) | - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => + ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) | + ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) | + ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) => collect_miri(tcx, ptr.alloc_id, output), - ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => { - // by ref should only collect the inner allocation, not the value itself - let alloc = tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .expect("ByRef to extern static is not allowed"); - for &inner in alloc.relocations.values() { - collect_miri(tcx, inner, output); + ConstVal::Value(ConstValue::ByRef(alloc)) => { + for &id in alloc.relocations.values() { + collect_miri(tcx, id, output); } } _ => {}, diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 176ed8c5bca..a569ad00d0c 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -313,8 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::TyArray(inner_type, len) => { output.push('['); self.push_type_name(inner_type, output); - write!(output, "; {}", - len.val.unwrap_u64()).unwrap(); + write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 699a5b17435..5b2f3a8b8aa 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -11,12 +11,10 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer; -use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; -use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +301,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), ty::TyArray(ty, len) => { - let len = len.val.unwrap_u64(); + let len = len.unwrap_usize(tcx); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -442,11 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: func_ty - }), + value: ty::Const::zero_sized(self.tcx, func_ty) }, }); @@ -506,10 +500,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))), - ty: self.tcx.types.usize, - }) + value: ty::Const::from_usize(self.tcx, value), } } } @@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }), + value: ty::Const::zero_sized(tcx, ty) }, }), vec![rcvr]) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e1db216b6bb..6b0217c8f7c 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -19,15 +19,17 @@ use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionE use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; -use rustc::mir::interpret::{Value, PrimVal, GlobalId}; +use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult}; +use interpret::EvalContext; +use interpret::CompileTimeEvaluator; use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy}; use transform::{MirPass, MirSource}; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use rustc::ty::subst::Substs; use rustc_data_structures::indexed_vec::IndexVec; use rustc::ty::ParamEnv; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, + LayoutOf, TyLayout, LayoutError, LayoutCx, HasTyCtxt, TargetDataLayout, HasDataLayout, }; @@ -64,6 +66,7 @@ type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); /// Finds optimization opportunities on the MIR. struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { + ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>, mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, @@ -102,7 +105,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { source: MirSource, ) -> ConstPropagator<'b, 'a, 'tcx> { let param_env = tcx.param_env(source.def_id); + let substs = Substs::identity_for_item(tcx, source.def_id); + let instance = Instance::new(source.def_id, substs); + let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap(); ConstPropagator { + ecx, mir, tcx, source, @@ -112,7 +119,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } } - fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option> { + fn use_ecx( + &mut self, + span: Span, + f: F + ) -> Option + where + F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, + { + self.ecx.tcx.span = span; + let r = match f(self) { + Ok(val) => Some(val), + Err(mut err) => { + self.ecx.report(&mut err, false, Some(span)); + None + }, + }; + self.ecx.tcx.span = DUMMY_SP; + r + } + + fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option> { let value = match self.tcx.const_eval(self.param_env.and(cid)) { Ok(val) => val, Err(err) => { @@ -121,7 +148,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { }, }; let val = match value.val { - ConstVal::Value(v) => v, + ConstVal::Value(v) => { + self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))? + }, _ => bug!("eval produced: {:?}", value), }; let val = (val, value.ty, span); @@ -132,7 +161,12 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { match c.literal { Literal::Value { value } => match value.val { - ConstVal::Value(v) => Some((v, value.ty, c.span)), + ConstVal::Value(v) => { + let v = self.use_ecx(c.span, |this| { + this.ecx.const_value_to_value(v, value.ty) + })?; + Some((v, value.ty, c.span)) + }, ConstVal::Unevaluated(did, substs) => { let instance = Instance::resolve( self.tcx, @@ -162,7 +196,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { }; // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now - let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?; + let span = self.mir.span; + let (value, _, ty) = self.use_ecx(span, |this| { + Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)) + })??; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); Some(val) @@ -185,7 +222,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { use rustc_data_structures::indexed_vec::Idx; let field_index = field.index(); let val = [a, b][field_index]; - let field = base_layout.field(&*self, field_index).ok()?; + let cx = LayoutCx { + tcx: self.tcx, + param_env: self.param_env, + }; + let field = base_layout.field(cx, field_index).ok()?; trace!("projection resulted in: {:?}", val); Some((Value::ByVal(val), field.ty, span)) }, @@ -258,19 +299,13 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { // FIXME: can't handle code with generics return None; } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); let val = self.eval_operand(arg)?; - let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; - match ecx.unary_op(op, prim, val.1) { - Ok(val) => Some((Value::ByVal(val), place_ty, span)), - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } + let prim = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }) + })?; + let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?; + Some((Value::ByVal(val), place_ty, span)) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -287,11 +322,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { // FIXME: can't handle code with generics return None; } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + let r = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }) + })?; if op == BinOp::Shr || op == BinOp::Shl { let param_env = self.tcx.param_env(self.source.def_id); let left_ty = left.ty(self.mir, self.tcx); @@ -316,31 +350,31 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } } let left = self.eval_operand(left)?; - let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; + let l = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }) + })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); - match ecx.binary_op(op, l, left.1, r, right.1) { - Ok((val, overflow)) => { - let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { - Value::ByValPair( - val, - PrimVal::from_bool(overflow), - ) - } else { - if overflow { - use rustc::mir::interpret::EvalErrorKind; - let mut err = EvalErrorKind::Overflow(op).into(); - ecx.report(&mut err, false, Some(span)); - return None; - } - Value::ByVal(val) - }; - Some((val, place_ty, span)) - }, - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } + let (val, overflow) = self.use_ecx(span, |this| { + this.ecx.binary_op(op, l, left.1, r, right.1) + })?; + let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { + Value::ByValPair( + val, + PrimVal::from_bool(overflow), + ) + } else { + if overflow { + use rustc::mir::interpret::EvalErrorKind; + let mut err = EvalErrorKind::Overflow(op).into(); + self.use_ecx(span, |this| { + this.ecx.report(&mut err, false, Some(span)); + Ok(()) + }); + return None; + } + Value::ByVal(val) + }; + Some((val, place_ty, span)) }, } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5397d18cdd7..0666209d4f1 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -17,8 +17,6 @@ use dataflow::MoveDataParamEnv; use dataflow::{self, do_dataflow, DebugFormatted}; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; -use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; @@ -533,10 +531,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, val) } }))) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c4e700cdd1f..5da40d04b33 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -61,7 +61,6 @@ use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty}; @@ -79,7 +78,6 @@ use transform::simplify; use transform::no_landing_pads::no_landing_pads; use dataflow::{do_dataflow, DebugFormatted, state_for_location}; use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; -use rustc::mir::interpret::{Value, PrimVal}; pub struct StateTransform; @@ -180,10 +178,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { span: source_info.span, ty: self.tcx.types.u32, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))), - ty: self.tcx.types.u32 - }), + value: ty::Const::from_bits( + self.tcx, + state_disc.into(), + self.tcx.types.u32), }, }); Statement { @@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: tcx.types.bool - }), + value: ty::Const::from_bool(tcx, false), }, }), expected: true, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4762c6aaa27..28ab3d6a857 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Operand::Constant(ref constant) => { if let Literal::Value { - value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty } + value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. } } = constant.literal { // Don't peek inside trait associated constants. if self.tcx.trait_of_item(def_id).is_some() { @@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { _ => false } } else if let ty::TyArray(_, len) = ty.sty { - len.val.unwrap_u64() == 0 && + len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn } else { false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 9dd48952208..72bee040c06 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -10,10 +10,8 @@ //! A pass that simplifies branches when their condition is known. -use rustc::ty::{self, TyCtxt}; -use rustc::middle::const_val::ConstVal; +use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal}; use transform::{MirPass, MirSource}; use std::borrow::Cow; @@ -32,7 +30,7 @@ impl MirPass for SimplifyBranches { } fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { for block in mir.basic_blocks_mut() { @@ -40,8 +38,8 @@ impl MirPass for SimplifyBranches { terminator.kind = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. - }), ref values, ref targets, .. } => { - if let Some(constint) = value.val.to_raw_bits() { + }), switch_ty, ref values, ref targets, .. } => { + if let Some(constint) = value.assert_bits(switch_ty) { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; for (&v, t) in values.iter().zip(targets.iter()) { @@ -57,12 +55,9 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(box Constant { literal: Literal::Value { - value: &ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))), - .. } + value }, .. - }), expected, .. } if (cond == 1) == expected => { - assert!(cond <= 1); + }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => { TerminatorKind::Goto { target: target } }, TerminatorKind::FalseEdges { real_target, .. } => { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 9cc3ffb3063..5019c74742a 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -81,9 +81,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { } else { let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); if let ty::TyArray(item_ty, const_size) = place_ty.sty { - if let Some(size) = const_size.val.to_raw_bits() { - assert!(size <= (u32::max_value() as u128), - "unform array move out doesn't supported + if let Some(size) = const_size.assert_usize(self.tcx) { + assert!(size <= u32::max_value() as u64, + "uniform array move out doesn't supported for array bigger then u32"); self.uniform(location, dst_place, proj, item_ty, size as u32); } @@ -203,7 +203,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_size = opt_src_place.and_then(|src_place| { let src_ty = src_place.ty(mir, tcx).to_ty(tcx); if let ty::TyArray(_, ref size_o) = src_ty.sty { - size_o.val.to_raw_bits().map(|n| n as u64) + size_o.assert_usize(tcx) } else { None } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index a641cf3d93e..9fc04dc7d24 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,7 +11,6 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; @@ -19,7 +18,6 @@ use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; -use rustc::mir::interpret::{Value, PrimVal}; use std::{iter, u32}; @@ -809,8 +807,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let succ = self.succ; self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } - ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_raw_bits().map(|i| i as u64)), + ty::TyArray(ety, size) => { + let size = size.assert_usize(self.tcx()); + self.open_drop_for_array(ety, size) + }, ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -961,10 +961,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, literal: Literal::Value { - value: self.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))), - ty: self.tcx().types.usize - }) + value: ty::Const::from_usize(self.tcx(), val.into()) } }) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 71012ca6d5f..9d74ad0830f 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -402,7 +402,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); - let ty::Const { ty, val } = constant; + let ty::Const { ty, val, .. } = constant; self.push(&format!("ty::Const")); self.push(&format!("+ ty: {:?}", ty)); self.push(&format!("+ val: {:?}", val)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 33dc9b3b7ab..54177c5d5a2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -199,7 +199,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.unwrap_u64()) + C_usize(cx, len.unwrap_usize(cx.tcx)) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker @@ -1372,8 +1372,7 @@ mod temp_stable_hash_impls { } fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { - use rustc::mir::interpret::{GlobalId, Value, PrimVal}; - use rustc::middle::const_val::ConstVal; + use rustc::mir::interpret::GlobalId; info!("loading wasm section {:?}", id); @@ -1392,18 +1391,7 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { let param_env = ty::ParamEnv::reveal_all(); let val = tcx.const_eval(param_env.and(cid)).unwrap(); - let val = match val.val { - ConstVal::Value(val) => val, - ConstVal::Unevaluated(..) => bug!("should be evaluated"), - }; - let val = match val { - Value::ByRef(ptr, _align) => ptr.into_inner_primval(), - ref v => bug!("should be ByRef, was {:?}", v), - }; - let mem = match val { - PrimVal::Ptr(mem) => mem, - ref v => bug!("should be Ptr, was {:?}", v), - }; + let mem = val.to_ptr().expect("should be pointer"); assert_eq!(mem.offset, 0); let alloc = tcx .interpret_interner diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ae23b523cbf..4e77c0df65e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -277,7 +277,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.unwrap_u64() as c_longlong + len.unwrap_usize(cx.tcx) as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 565a9bedef0..05a74db3a6c 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.unwrap_u64())); + output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 6e07b8e73ef..a10b7c9c9f1 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -14,7 +14,7 @@ use rustc_mir::interpret::{read_target_uint, const_val_field}; use rustc::hir::def_id::DefId; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue}; +use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue}; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; use builder::Builder; @@ -56,7 +56,7 @@ pub fn primval_to_llvm(cx: &CodegenCx, consts::get_static(cx, def_id) } else if let Some(alloc) = cx.tcx.interpret_interner .get_alloc(ptr.alloc_id) { - let init = global_initializer(cx, alloc); + let init = const_alloc_to_llvm(cx, alloc); if alloc.runtime_mutability == Mutability::Mutable { consts::addr_of_mut(cx, init, alloc.align, "byte_str") } else { @@ -81,7 +81,50 @@ pub fn primval_to_llvm(cx: &CodegenCx, } } -pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { +fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { + let layout = cx.layout_of(ty); + + if layout.is_zst() { + return C_undef(layout.immediate_llvm_type(cx)); + } + + match val { + ConstValue::ByVal(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) + }; + primval_to_llvm( + cx, + x, + scalar, + layout.immediate_llvm_type(cx), + ) + }, + ConstValue::ByValPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + cx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(cx, 0), + ); + let b_llval = primval_to_llvm( + cx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(cx, 1), + ); + C_struct(cx, &[a_llval, b_llval], false) + }, + ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), + } +} + +pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); let layout = cx.data_layout(); let pointer_size = layout.pointer_size.bytes() as usize; @@ -96,7 +139,7 @@ pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let ptr_offset = read_target_uint( layout.endian, &alloc.bytes[offset..(offset + pointer_size)], - ).expect("global_initializer: could not read relocation pointer") as u64; + ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(primval_to_llvm( cx, PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), @@ -128,25 +171,19 @@ pub fn trans_static_initializer<'a, 'tcx>( let param_env = ty::ParamEnv::reveal_all(); let static_ = cx.tcx.const_eval(param_env.and(cid))?; - let ptr = match static_.val { - ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr, + let val = match static_.val { + ConstVal::Value(val) => val, _ => bug!("static const eval returned {:#?}", static_), }; - - let alloc = cx - .tcx - .interpret_interner - .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id) - .expect("miri allocation never successfully created"); - Ok(global_initializer(cx, alloc)) + Ok(const_value_to_llvm(cx, val, static_.ty)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - fn const_to_miri_value( + fn const_to_const_value( &mut self, bx: &Builder<'a, 'tcx>, constant: &'tcx ty::Const<'tcx>, - ) -> Result> { + ) -> Result, ConstEvalErr<'tcx>> { match constant.val { ConstVal::Unevaluated(def_id, ref substs) => { let tcx = bx.tcx(); @@ -157,17 +194,17 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { promoted: None, }; let c = tcx.const_eval(param_env.and(cid))?; - self.const_to_miri_value(bx, c) + self.const_to_const_value(bx, c) }, - ConstVal::Value(miri_val) => Ok(miri_val), + ConstVal::Value(val) => Ok(val), } } - pub fn mir_constant_to_miri_value( + pub fn mir_constant_to_const_value( &mut self, bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, - ) -> Result> { + ) -> Result, ConstEvalErr<'tcx>> { match constant.literal { mir::Literal::Promoted { index } => { let param_env = ty::ParamEnv::reveal_all(); @@ -180,7 +217,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Literal::Value { value } => { Ok(self.monomorphize(&value)) } - }.and_then(|c| self.const_to_miri_value(bx, c)) + }.and_then(|c| self.const_to_const_value(bx, c)) } /// process constant containing SIMD shuffle indices @@ -189,11 +226,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, ) -> (ValueRef, Ty<'tcx>) { - self.mir_constant_to_miri_value(bx, constant) + self.mir_constant_to_const_value(bx, constant) .and_then(|c| { let field_ty = constant.ty.builtin_index().unwrap(); let fields = match constant.ty.sty { - ty::TyArray(_, n) => n.val.unwrap_u64(), + ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()), ref other => bug!("invalid simd shuffle type: {}", other), }; let values: Result, _> = (0..fields).map(|field| { @@ -206,19 +243,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { c, constant.ty, )?; - match field.val { - ConstVal::Value(MiriValue::ByVal(prim)) => { - let layout = bx.cx.layout_of(field_ty); - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - Ok(primval_to_llvm( - bx.cx, prim, scalar, - layout.immediate_llvm_type(bx.cx), - )) - }, - other => bug!("simd shuffle field {:?}, {}", other, constant.ty), + if let Some(prim) = field.to_primval() { + let layout = bx.cx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(primval_to_llvm( + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), + )) + } else { + bug!("simd shuffle field {:?}", field) } }).collect(); let llval = C_struct(bx.cx, &values?, false); diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 656ab95a28c..432ac44e0a5 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -11,7 +11,7 @@ use llvm::ValueRef; use rustc::middle::const_val::ConstEvalErr; use rustc::mir; -use rustc::mir::interpret::Value as MiriValue; +use rustc::mir::interpret::ConstValue; use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; @@ -22,12 +22,13 @@ use builder::Builder; use value::Value; use type_of::LayoutLlvmExt; use type_::Type; +use consts; use std::fmt; use std::ptr; use super::{FunctionCx, LocalRef}; -use super::constant::{primval_to_llvm}; +use super::constant::{primval_to_llvm, const_alloc_to_llvm}; use super::place::PlaceRef; /// The representation of a Rust value. The enum variant is in fact @@ -94,7 +95,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { } pub fn from_const(bx: &Builder<'a, 'tcx>, - miri_val: MiriValue, + val: ConstValue<'tcx>, ty: ty::Ty<'tcx>) -> Result, ConstEvalErr<'tcx>> { let layout = bx.cx.layout_of(ty); @@ -103,8 +104,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { return Ok(OperandRef::new_zst(bx.cx, layout)); } - let val = match miri_val { - MiriValue::ByVal(x) => { + let val = match val { + ConstValue::ByVal(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) @@ -117,7 +118,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { ); OperandValue::Immediate(llval) }, - MiriValue::ByValPair(a, b) => { + ConstValue::ByValPair(a, b) => { let (a_scalar, b_scalar) = match layout.abi { layout::Abi::ScalarPair(ref a, ref b) => (a, b), _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) @@ -136,18 +137,11 @@ impl<'a, 'tcx> OperandRef<'tcx> { ); OperandValue::Pair(a_llval, b_llval) }, - MiriValue::ByRef(ptr, align) => { - let scalar = layout::Scalar { - value: layout::Primitive::Pointer, - valid_range: 0..=!0 - }; - let ptr = primval_to_llvm( - bx.cx, - ptr.into_inner_primval(), - &scalar, - layout.llvm_type(bx.cx).ptr_to(), - ); - return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx)); + ConstValue::ByRef(alloc) => { + let init = const_alloc_to_llvm(bx.cx, alloc); + let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); + return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx)); }, }; @@ -396,7 +390,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Operand::Constant(ref constant) => { let ty = self.monomorphize(&constant.ty); - self.mir_constant_to_miri_value(bx, constant) + self.mir_constant_to_const_value(bx, constant) .and_then(|c| OperandRef::from_const(bx, c, ty)) .unwrap_or_else(|err| { match constant.literal { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 0cd823391b9..3b447756450 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -516,7 +516,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.unwrap_u64(); + let n = n.unwrap_usize(bx.cx.tcx); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 93dbba6e873..d307ef30044 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,6 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc::middle::const_val::ConstVal; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1087,10 +1086,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyArray(ref ty, length) => { let length_def_id = tcx.hir.body_owner_def_id(length); let substs = Substs::identity_for_item(tcx, length_def_id); - let length = tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(length_def_id, substs), - ty: tcx.types.usize - }); + let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize); let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c7585c827ce..2547952d104 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -375,7 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let size = size.val.unwrap_u64(); + let size = size.unwrap_usize(tcx); let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ef14fa9a122..7b859635f60 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4018,7 +4018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1); + let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 007938e86ed..3ffdd5595a2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2644,10 +2644,7 @@ impl Clean for hir::Ty { promoted: None }; let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| { - cx.tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(def_id, substs), - ty: cx.tcx.types.usize - }) + ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize) }); let n = print_const(cx, n); Array(box ty.clean(cx), n) @@ -3828,9 +3825,9 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String { inline::print_inlined_const(cx, def_id) } }, - ConstVal::Value(val) => { + ConstVal::Value(..) => { let mut s = String::new(); - ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); + ::rustc::mir::fmt_const_val(&mut s, n).unwrap(); // array lengths are obviously usize if s.ends_with("usize") { let n = s.len() - "usize".len(); diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 415ee6eb7ea..1879002e7f3 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,17 +12,11 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" +// CHECK: @VAR1 = constant i32 1, section ".test_one" #[no_mangle] #[link_section = ".test_one"] -#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; -#[no_mangle] -#[link_section = ".test_one"] -#[cfg(target_endian = "big")] -pub static VAR1: u32 = 0x01000000; - pub enum E { A(u32), B(f32) -- cgit 1.4.1-3-g733a5 From 12308139ec76dfa050ed012606495250391aaf74 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 14 May 2018 15:20:51 +0200 Subject: Emit noalias on &mut parameters by default This used to be disabled due to LLVM bugs in the handling of noalias information in conjunction with unwinding. However, according to #31681 all known LLVM bugs have been fixed by LLVM 6.0, so it's probably time to reenable this optimization. Noalias annotations will not be emitted by default if either -C panic=abort (as previously) or LLVM >= 6.0 (new). -Z mutable-noalias=no is left as an escape-hatch to allow debugging problems suspected to stem from this change. --- src/librustc/session/config.rs | 4 ++-- src/librustc_codegen_llvm/type_of.rs | 10 ++++++++-- src/test/codegen/function-arguments.rs | 10 ++++------ 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2344cd11f66..bcad3fbc841 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1239,8 +1239,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the result of the monomorphization collection pass"), mir_opt_level: usize = (1, parse_uint, [TRACKED], "set the MIR optimization level (0-3, default: 1)"), - mutable_noalias: bool = (false, parse_bool, [TRACKED], - "emit noalias metadata for mutable references"), + mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], + "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"), arg_align_attributes: bool = (false, parse_bool, [TRACKED], "emit align metadata for reference arguments"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 5f186e7514e..21436b74731 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -10,6 +10,7 @@ use abi::{FnType, FnTypeExt}; use common::*; +use llvm; use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; @@ -428,8 +429,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { PointerKind::Shared }, hir::MutMutable => { - if cx.tcx.sess.opts.debugging_opts.mutable_noalias || - cx.tcx.sess.panic_strategy() == PanicStrategy::Abort { + // Only emit noalias annotations for LLVM >= 6 or in panic=abort + // mode, as prior versions had many bugs in conjunction with + // unwinding. See also issue #31681. + let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias + .unwrap_or(unsafe { llvm::LLVMRustVersionMajor() >= 6 } + || cx.tcx.sess.panic_strategy() == PanicStrategy::Abort); + if mutable_noalias { PointerKind::UniqueBorrowed } else { PointerKind::Shared diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 40a9ea5a181..e3fa7a7db39 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -10,6 +10,7 @@ // compile-flags: -C no-prepopulate-passes // ignore-tidy-linelength +// min-llvm-version 6.0 #![crate_type = "lib"] #![feature(custom_attribute)] @@ -52,16 +53,14 @@ pub fn named_borrow<'r>(_: &'r i32) { pub fn unsafe_borrow(_: &UnsafeInner) { } -// CHECK: @mutable_unsafe_borrow(i16* dereferenceable(2) %arg0) +// CHECK: @mutable_unsafe_borrow(i16* noalias dereferenceable(2) %arg0) // ... unless this is a mutable borrow, those never alias -// ... except that there's this LLVM bug that forces us to not use noalias, see #29485 #[no_mangle] pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) { } -// CHECK: @mutable_borrow(i32* dereferenceable(4) %arg0) +// CHECK: @mutable_borrow(i32* noalias dereferenceable(4) %arg0) // FIXME #25759 This should also have `nocapture` -// ... there's this LLVM bug that forces us to not use noalias, see #29485 #[no_mangle] pub fn mutable_borrow(_: &mut i32) { } @@ -103,9 +102,8 @@ pub fn helper(_: usize) { pub fn slice(_: &[u8]) { } -// CHECK: @mutable_slice([0 x i8]* nonnull %arg0.0, [[USIZE]] %arg0.1) +// CHECK: @mutable_slice([0 x i8]* noalias nonnull %arg0.0, [[USIZE]] %arg0.1) // FIXME #25759 This should also have `nocapture` -// ... there's this LLVM bug that forces us to not use noalias, see #29485 #[no_mangle] pub fn mutable_slice(_: &mut [u8]) { } -- cgit 1.4.1-3-g733a5 From 8b99c61701cd3230bb24fba970d2f400e6e09fa1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 12 May 2018 18:47:20 +0200 Subject: Ensure that statics are always ByRef --- src/librustc_codegen_llvm/mir/constant.rs | 49 +--------- src/librustc_mir/interpret/const_eval.rs | 145 ++++++++++++------------------ src/test/codegen/link_section.rs | 8 +- 3 files changed, 69 insertions(+), 133 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index c2638d2d410..66a8b3ca36f 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -81,49 +81,6 @@ pub fn primval_to_llvm(cx: &CodegenCx, } } -fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { - let layout = cx.layout_of(ty); - - if layout.is_zst() { - return C_undef(layout.immediate_llvm_type(cx)); - } - - match val { - ConstValue::ByVal(x) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) - }; - primval_to_llvm( - cx, - x, - scalar, - layout.immediate_llvm_type(cx), - ) - }, - ConstValue::ByValPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) - }; - let a_llval = primval_to_llvm( - cx, - a, - a_scalar, - layout.scalar_pair_element_llvm_type(cx, 0), - ); - let b_llval = primval_to_llvm( - cx, - b, - b_scalar, - layout.scalar_pair_element_llvm_type(cx, 1), - ); - C_struct(cx, &[a_llval, b_llval], false) - }, - ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), - } -} - pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); let layout = cx.data_layout(); @@ -171,11 +128,11 @@ pub fn codegen_static_initializer<'a, 'tcx>( let param_env = ty::ParamEnv::reveal_all(); let static_ = cx.tcx.const_eval(param_env.and(cid))?; - let val = match static_.val { - ConstVal::Value(val) => val, + let alloc = match static_.val { + ConstVal::Value(ConstValue::ByRef(alloc)) => alloc, _ => bug!("static const eval returned {:#?}", static_), }; - Ok(const_value_to_llvm(cx, val, static_.ty)) + Ok(const_alloc_to_llvm(cx, alloc)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 7d0c16de0a4..1f368cd3dfc 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -98,59 +98,32 @@ pub fn value_to_const_value<'tcx>( mut val: Value, ty: Ty<'tcx>, ) -> &'tcx ty::Const<'tcx> { - let result = (|| { + let val = (|| { // Convert to ByVal or ByValPair if possible if let Value::ByRef(ptr, align) = val { if let Some(read_val) = ecx.try_read_value(ptr, align, ty)? { val = read_val; } } - - let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); - - if layout.is_zst() { - return Ok(ty::Const::from_const_value( - ecx.tcx.tcx, - ConstValue::ByVal(PrimVal::Undef), - ty)); - } - - let val = match layout.abi { - layout::Abi::Scalar(..) => { - if let Value::ByVal(val) = val { - ConstValue::ByVal(val) - } else { - bug!("expected ByVal value, got {:?}", val); - } - } - layout::Abi::ScalarPair(..) => { - if let Value::ByValPair(a, b) = val { - ConstValue::ByValPair(a, b) - } else { - bug!("expected ByValPair value, got {:?}", val); - } + match val { + Value::ByVal(val) => Ok(ConstValue::ByVal(val)), + Value::ByValPair(a, b) => Ok(ConstValue::ByValPair(a, b)), + Value::ByRef(ptr, align) => { + let ptr = ptr.primval.to_ptr().unwrap(); + assert_eq!(ptr.offset, 0); + let alloc = ecx.memory.get(ptr.alloc_id)?; + assert!(alloc.align.abi() >= layout.align.abi()); + assert!(alloc.bytes.len() as u64 == layout.size.bytes()); + let mut alloc = alloc.clone(); + // The align field is meaningless for values, so just use the layout's align + alloc.align = layout.align; + let alloc = ecx.tcx.intern_const_alloc(alloc); + Ok(ConstValue::ByRef(alloc)) } - _ => { - if let Value::ByRef(ptr, _) = val { - let ptr = ptr.primval.to_ptr().unwrap(); - assert_eq!(ptr.offset, 0); - let alloc = ecx.memory.get(ptr.alloc_id)?; - assert!(alloc.align.abi() >= layout.align.abi()); - assert!(alloc.bytes.len() as u64 == layout.size.bytes()); - let mut alloc = alloc.clone(); - // The align field is meaningless for values, so just use the layout's align - alloc.align = layout.align; - let alloc = ecx.tcx.intern_const_alloc(alloc); - ConstValue::ByRef(alloc) - } else { - bug!("expected ByRef value, got {:?}", val); - } - }, - }; - Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, ty)) + } })(); match result { - Ok(v) => v, + Ok(v) => ty::Const::from_const_value(tcx, val, ty), Err(mut err) => { ecx.report(&mut err, true, None); bug!("miri error occured when converting Value to ConstValue") @@ -182,49 +155,49 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", cid, param_env); let tcx = ecx.tcx.tcx; - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; + let mut mir = match mir { + Some(mir) => mir, + None => ecx.load_mir(cid.instance.def)?, + }; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let is_static = tcx.is_static(cid.instance.def_id()); + let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; - while ecx.step()? {} - let ptr = ptr.into(); - // always try to read the value and report errors - let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { - Some(val) => val, - // point at the allocation - _ => Value::ByRef(ptr, layout.align), - }; - Ok((value, ptr, layout.ty)) + while ecx.step()? {} + let ptr = ptr.into(); + // always try to read the value and report errors + let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { + Some(val) if is_static.is_none() => val, + // point at the allocation + _ => Value::ByRef(ptr, layout.align), + }; + Ok((value, ptr, layout.ty)) } pub struct CompileTimeEvaluator; diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 1879002e7f3..415ee6eb7ea 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,11 +12,17 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant i32 1, section ".test_one" +// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] +#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "big")] +pub static VAR1: u32 = 0x01000000; + pub enum E { A(u32), B(f32) -- cgit 1.4.1-3-g733a5 From 729c22e7979ca2f1f82caedf5a7b245d59ea6dbc Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 4 May 2018 18:40:46 +0200 Subject: move simd-minmax-test to run-pass; require llvm 7 --- src/test/codegen/simd-intrinsic-float-minmax.rs | 2 +- src/test/run-fail/simd-intrinsic-float-minmax.rs | 57 ------------------------ src/test/run-pass/simd-intrinsic-float-minmax.rs | 56 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 58 deletions(-) delete mode 100644 src/test/run-fail/simd-intrinsic-float-minmax.rs create mode 100644 src/test/run-pass/simd-intrinsic-float-minmax.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index 6663b841808..d963c7e8ddf 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -16,7 +16,7 @@ #![crate_type = "lib"] #![feature(repr_simd, platform_intrinsics)] -#[allow(non_camel_case_types)] +#![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs deleted file mode 100644 index f4fb8e12250..00000000000 --- a/src/test/run-fail/simd-intrinsic-float-minmax.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-emscripten -// min-llvm-version 6.0 -// error-pattern: panicked - -// Test that the simd_f{min,max} intrinsics produce the correct results. - -#![feature(repr_simd, platform_intrinsics)] -#[allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_fmin(x: T, y: T) -> T; - fn simd_fmax(x: T, y: T) -> T; -} - -fn main() { - let x = f32x4(1.0, 2.0, 3.0, 4.0); - let y = f32x4(2.0, 1.0, 4.0, 3.0); - let nan = ::std::f32::NAN; - let n = f32x4(nan, nan, nan, nan); - - unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); - assert_eq!(min0, min1); - let e = f32x4(1.0, 1.0, 3.0, 3.0); - assert_eq!(min0, e); - let minn = simd_fmin(x, n); - assert_eq!(minn, x); - let minn = simd_fmin(y, n); - assert_eq!(minn, y); - - // FIXME(49261) - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); - assert_eq!(max0, max1); - let e = f32x4(2.0, 2.0, 4.0, 4.0); - assert_eq!(max0, e); - let maxn = simd_fmax(x, n); - assert_eq!(maxn, x); - let maxn = simd_fmax(y, n); - assert_eq!(maxn, y); - } -} diff --git a/src/test/run-pass/simd-intrinsic-float-minmax.rs b/src/test/run-pass/simd-intrinsic-float-minmax.rs new file mode 100644 index 00000000000..71c0139bb03 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-float-minmax.rs @@ -0,0 +1,56 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten +// min-llvm-version 7.0 +// error-pattern: panicked + +// Test that the simd_f{min,max} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +fn main() { + let x = f32x4(1.0, 2.0, 3.0, 4.0); + let y = f32x4(2.0, 1.0, 4.0, 3.0); + let nan = ::std::f32::NAN; + let n = f32x4(nan, nan, nan, nan); + + unsafe { + let min0 = simd_fmin(x, y); + let min1 = simd_fmin(y, x); + assert_eq!(min0, min1); + let e = f32x4(1.0, 1.0, 3.0, 3.0); + assert_eq!(min0, e); + let minn = simd_fmin(x, n); + assert_eq!(minn, x); + let minn = simd_fmin(y, n); + assert_eq!(minn, y); + + let max0 = simd_fmax(x, y); + let max1 = simd_fmax(y, x); + assert_eq!(max0, max1); + let e = f32x4(2.0, 2.0, 4.0, 4.0); + assert_eq!(max0, e); + let maxn = simd_fmax(x, n); + assert_eq!(maxn, x); + let maxn = simd_fmax(y, n); + assert_eq!(maxn, y); + } +} -- cgit 1.4.1-3-g733a5 From f8f204c0bf03ccb0a87940803fddb8f631a92afd Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 4 May 2018 20:07:35 +0200 Subject: add simd float intrinsics and gather/scatter --- src/librustc_codegen_llvm/context.rs | 117 +++++++ src/librustc_codegen_llvm/intrinsic.rs | 371 +++++++++++++++++++++ src/librustc_typeck/check/intrinsic.rs | 19 +- src/test/codegen/simd-intrinsic-float-abs.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-ceil.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-cos.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-exp.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-exp2.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-floor.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-fma.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-fsqrt.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-log10.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-log2.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-pow.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-powi.rs | 104 ++++++ src/test/codegen/simd-intrinsic-float-sin.rs | 104 ++++++ src/test/codegen/simd-intrinsic-generic-gather.rs | 46 +++ src/test/codegen/simd-intrinsic-generic-scatter.rs | 46 +++ 18 files changed, 1950 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/simd-intrinsic-float-abs.rs create mode 100644 src/test/codegen/simd-intrinsic-float-ceil.rs create mode 100644 src/test/codegen/simd-intrinsic-float-cos.rs create mode 100644 src/test/codegen/simd-intrinsic-float-exp.rs create mode 100644 src/test/codegen/simd-intrinsic-float-exp2.rs create mode 100644 src/test/codegen/simd-intrinsic-float-floor.rs create mode 100644 src/test/codegen/simd-intrinsic-float-fma.rs create mode 100644 src/test/codegen/simd-intrinsic-float-fsqrt.rs create mode 100644 src/test/codegen/simd-intrinsic-float-log10.rs create mode 100644 src/test/codegen/simd-intrinsic-float-log2.rs create mode 100644 src/test/codegen/simd-intrinsic-float-pow.rs create mode 100644 src/test/codegen/simd-intrinsic-float-powi.rs create mode 100644 src/test/codegen/simd-intrinsic-float-sin.rs create mode 100644 src/test/codegen/simd-intrinsic-generic-gather.rs create mode 100644 src/test/codegen/simd-intrinsic-generic-scatter.rs (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 9b1de3d44ea..b774d7c5def 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -522,6 +522,15 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { let t_f32 = Type::f32(cx); let t_f64 = Type::f64(cx); + let t_v2f32 = Type::vector(&t_f32, 2); + let t_v4f32 = Type::vector(&t_f32, 4); + let t_v8f32 = Type::vector(&t_f32, 8); + let t_v16f32 = Type::vector(&t_f32, 16); + + let t_v2f64 = Type::vector(&t_f64, 2); + let t_v4f64 = Type::vector(&t_f64, 4); + let t_v8f64 = Type::vector(&t_f64, 8); + ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); @@ -537,37 +546,145 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { ifn!("llvm.frameaddress", fn(t_i32) -> i8p); ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); + ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32); + ifn!("llvm.powi.v4f32", fn(t_v4f32, t_i32) -> t_v4f32); + ifn!("llvm.powi.v8f32", fn(t_v8f32, t_i32) -> t_v8f32); + ifn!("llvm.powi.v16f32", fn(t_v16f32, t_i32) -> t_v16f32); ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); + ifn!("llvm.powi.v2f64", fn(t_v2f64, t_i32) -> t_v2f64); + ifn!("llvm.powi.v4f64", fn(t_v4f64, t_i32) -> t_v4f64); + ifn!("llvm.powi.v8f64", fn(t_v8f64, t_i32) -> t_v8f64); + ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.pow.v2f32", fn(t_v2f32, t_v2f32) -> t_v2f32); + ifn!("llvm.pow.v4f32", fn(t_v4f32, t_v4f32) -> t_v4f32); + ifn!("llvm.pow.v8f32", fn(t_v8f32, t_v8f32) -> t_v8f32); + ifn!("llvm.pow.v16f32", fn(t_v16f32, t_v16f32) -> t_v16f32); ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.pow.v2f64", fn(t_v2f64, t_v2f64) -> t_v2f64); + ifn!("llvm.pow.v4f64", fn(t_v4f64, t_v4f64) -> t_v4f64); + ifn!("llvm.pow.v8f64", fn(t_v8f64, t_v8f64) -> t_v8f64); ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sqrt.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.sqrt.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.sqrt.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.sqrt.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); + ifn!("llvm.sqrt.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.sqrt.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.sqrt.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sin.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.sin.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.sin.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.sin.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); + ifn!("llvm.sin.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.sin.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.sin.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); + ifn!("llvm.cos.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.cos.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.cos.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.cos.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); + ifn!("llvm.cos.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.cos.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.cos.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.exp.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.exp.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.exp.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.exp.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.exp.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp2.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.exp2.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.exp2.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.exp2.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp2.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.exp2.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.exp2.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.log.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.log.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log10.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log10.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log10.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log10.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log10.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log10.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log10.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log2.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log2.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log2.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log2.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log2.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log2.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log2.v8f64", fn(t_v8f64) -> t_v8f64); ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); + ifn!("llvm.fma.v2f32", fn(t_v2f32, t_v2f32, t_v2f32) -> t_v2f32); + ifn!("llvm.fma.v4f32", fn(t_v4f32, t_v4f32, t_v4f32) -> t_v4f32); + ifn!("llvm.fma.v8f32", fn(t_v8f32, t_v8f32, t_v8f32) -> t_v8f32); + ifn!("llvm.fma.v16f32", fn(t_v16f32, t_v16f32, t_v16f32) -> t_v16f32); ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); + ifn!("llvm.fma.v2f64", fn(t_v2f64, t_v2f64, t_v2f64) -> t_v2f64); + ifn!("llvm.fma.v4f64", fn(t_v4f64, t_v4f64, t_v4f64) -> t_v4f64); + ifn!("llvm.fma.v8f64", fn(t_v8f64, t_v8f64, t_v8f64) -> t_v8f64); ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); + ifn!("llvm.fabs.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.fabs.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.fabs.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.fabs.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); + ifn!("llvm.fabs.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64); ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); + ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.floor.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.floor.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); + ifn!("llvm.floor.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.floor.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.floor.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); + ifn!("llvm.ceil.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.ceil.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.ceil.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.ceil.v16f32", fn(t_v16f32) -> t_v16f32); ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); + ifn!("llvm.ceil.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.ceil.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.ceil.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index cffe7f79e97..71641a7f248 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1140,6 +1140,377 @@ fn generic_simd_intrinsic<'a, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + fn simd_simple_float_intrinsic<'a, 'tcx>(name: &str, in_elem: &::rustc::ty::TyS, in_ty: &::rustc::ty::TyS, + in_len: usize, bx: &Builder<'a, 'tcx>, span: Span, + args: &[OperandRef<'tcx>]) + -> Result { + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + span_invalid_monomorphization_error( + bx.sess(), span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", + $msg), + name, $($fmt)*)); + } + } + macro_rules! return_error { + ($($fmt: tt)*) => { + { + emit_error!($($fmt)*); + return Err(()); + } + } + } + let ety = match in_elem.sty { + ty::TyFloat(f) if f.bit_width() == 32 => { + if in_len < 2 || in_len > 16 { + return_error!("unsupported floating-point vector `{}` with length `{}` out-of-range [2, 16]", + in_ty, in_len); + } + "f32" + }, + ty::TyFloat(f) if f.bit_width() == 64 => { + if in_len < 2 || in_len > 8 { + return_error!("unsupported floating-point vector `{}` with length `{}` out-of-range [2, 8]", + in_ty, in_len); + } + "f64" + }, + ty::TyFloat(f) => { + return_error!("unsupported element type `{}` of floating-point vector `{}`", + f, in_ty); + }, + _ => { + return_error!("`{}` is not a floating-point type", in_ty); + } + }; + + let llvm_name = &format!("llvm.{0}.v{1}{2}", name, in_len, ety); + let intrinsic = bx.cx.get_intrinsic(&llvm_name); + return Ok(bx.call(intrinsic, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None)); + } + + if name == "simd_fsqrt" { + return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fsin" { + return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fcos" { + return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fabs" { + return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_floor" { + return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_ceil" { + return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fexp" { + return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fexp2" { + return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog10" { + return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog2" { + return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog" { + return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fpowi" { + return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fpow" { + return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fma" { + return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_gather" { + // simd_gather(values: , pointers: , + // mask: ) -> + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + require_simd!(ret_ty, "return"); + + // Of the same length: + require!(in_len == arg_tys[1].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], + arg_tys[1].simd_size(tcx)); + require!(in_len == arg_tys[2].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], + arg_tys[2].simd_size(tcx)); + + // The return type must match the first argument type + require!(ret_ty == in_ty, + "expected return type `{}`, found `{}`", + in_ty, ret_ty); + + // This counts how many pointers + fn ptr_count(t: ty::Ty) -> usize { + match t.sty { + ty::TyRawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: ty::Ty) -> ty::Ty { + match t.sty { + ty::TyRawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + ty::TyRawPtr(p) if p.ty == in_elem => (ptr_count(arg_tys[1].simd_type(tcx)), + non_ptr(arg_tys[1].simd_type(tcx))), + _ => { + require!(false, "expected element type `{}` of second argument `{}` \ + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*_ {}`", + arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx).sty, in_elem); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx))); + assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + + // The element type of the third argument must be a signed integer type of any width: + match arg_tys[2].simd_type(tcx).sty { + ty::TyInt(_) => (), + _ => { + require!(false, "expected element type `{}` of third argument `{}` \ + to be a signed integer type", + arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + } + } + + // Alignment of T, must be a constant integer value: + let alignment_ty = Type::i32(bx.cx); + let alignment = C_i32(bx.cx, bx.cx.align_of(in_elem).abi() as i32); + + // Truncate the mask vector to a vector of i1s: + let (mask, mask_ty) = { + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + (bx.trunc(args[2].immediate(), i1xn), i1xn) + }; + + // FIXME: use: + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 + fn llvm_vector_str(elem_ty: ty::Ty, vec_len: usize, no_pointers: usize) -> String { + let p0s: String = "p0".repeat(no_pointers); + match elem_ty.sty { + ty::TyInt(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyUint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyFloat(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), + _ => unreachable!(), + } + } + + fn llvm_vector_ty(cx: &CodegenCx, elem_ty: ty::Ty, vec_len: usize, + mut no_pointers: usize) -> Type { + // FIXME: use cx.layout_of(ty).llvm_type() ? + let mut elem_ty = match elem_ty.sty { + ty::TyInt(v) => Type::int_from_ty(cx, v), + ty::TyUint(v) => Type::uint_from_ty(cx, v), + ty::TyFloat(v) => Type::float_from_ty(cx, v), + _ => unreachable!(), + }; + while no_pointers > 0 { + elem_ty = elem_ty.ptr_to(); + no_pointers -= 1; + } + Type::vector(&elem_ty, vec_len as u64) + } + + + // Type of the vector of pointers: + let llvm_pointer_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + + // Type of the vector of elements: + let llvm_elem_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + + let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", + llvm_elem_vec_str, llvm_pointer_vec_str); + let f = declare::declare_cfn(bx.cx, &llvm_intrinsic, + Type::func(&[llvm_pointer_vec_ty, alignment_ty, mask_ty, + llvm_elem_vec_ty], &llvm_elem_vec_ty)); + llvm::SetUnnamedAddr(f, false); + let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], + None); + return Ok(v); + } + + if name == "simd_scatter" { + // simd_scatter(values: , pointers: , + // mask: ) -> () + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + + // Of the same length: + require!(in_len == arg_tys[1].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], + arg_tys[1].simd_size(tcx)); + require!(in_len == arg_tys[2].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], + arg_tys[2].simd_size(tcx)); + + // This counts how many pointers + fn ptr_count(t: ty::Ty) -> usize { + match t.sty { + ty::TyRawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: ty::Ty) -> ty::Ty { + match t.sty { + ty::TyRawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + ty::TyRawPtr(p) if p.ty == in_elem && p.mutbl == hir::MutMutable + => (ptr_count(arg_tys[1].simd_type(tcx)), + non_ptr(arg_tys[1].simd_type(tcx))), + _ => { + require!(false, "expected element type `{}` of second argument `{}` \ + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*mut {}`", + arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx).sty, in_elem); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx))); + assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + + // The element type of the third argument must be a signed integer type of any width: + match arg_tys[2].simd_type(tcx).sty { + ty::TyInt(_) => (), + _ => { + require!(false, "expected element type `{}` of third argument `{}` \ + to be a signed integer type", + arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + } + } + + // Alignment of T, must be a constant integer value: + let alignment_ty = Type::i32(bx.cx); + let alignment = C_i32(bx.cx, bx.cx.align_of(in_elem).abi() as i32); + + // Truncate the mask vector to a vector of i1s: + let (mask, mask_ty) = { + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + (bx.trunc(args[2].immediate(), i1xn), i1xn) + }; + + let ret_t = Type::void(bx.cx); + + // FIXME: use: + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 + fn llvm_vector_str(elem_ty: ty::Ty, vec_len: usize, no_pointers: usize) -> String { + let p0s: String = "p0".repeat(no_pointers); + match elem_ty.sty { + ty::TyInt(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyUint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyFloat(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), + _ => unreachable!(), + } + } + + fn llvm_vector_ty(cx: &CodegenCx, elem_ty: ty::Ty, vec_len: usize, + mut no_pointers: usize) -> Type { + // FIXME: use cx.layout_of(ty).llvm_type() ? + let mut elem_ty = match elem_ty.sty { + ty::TyInt(v) => Type::int_from_ty(cx, v), + ty::TyUint(v) => Type::uint_from_ty(cx, v), + ty::TyFloat(v) => Type::float_from_ty(cx, v), + _ => unreachable!(), + }; + while no_pointers > 0 { + elem_ty = elem_ty.ptr_to(); + no_pointers -= 1; + } + Type::vector(&elem_ty, vec_len as u64) + } + + + // Type of the vector of pointers: + let llvm_pointer_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + + // Type of the vector of elements: + let llvm_elem_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + + let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", + llvm_elem_vec_str, llvm_pointer_vec_str); + let f = declare::declare_cfn(bx.cx, &llvm_intrinsic, + Type::func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], &ret_t)); + llvm::SetUnnamedAddr(f, false); + let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], + None); + return Ok(v); + } + macro_rules! arith_red { ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { if name == $name { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index af1f1044edf..5546aa58d4c 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -351,9 +351,26 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "simd_add" | "simd_sub" | "simd_mul" | "simd_rem" | "simd_div" | "simd_shl" | "simd_shr" | "simd_and" | "simd_or" | "simd_xor" | - "simd_fmin" | "simd_fmax" => { + "simd_fmin" | "simd_fmax" | "simd_fpow" => { (1, vec![param(0), param(0)], param(0)) } + "simd_fsqrt" | "simd_fsin" | "simd_fcos" | "simd_fexp" | "simd_fexp2" | + "simd_flog2" | "simd_flog10" | "simd_flog" | + "simd_fabs" | "simd_floor" | "simd_ceil" => { + (1, vec![param(0)], param(0)) + } + "simd_fpowi" => { + (1, vec![param(0), tcx.types.i32], param(0)) + } + "simd_fma" => { + (1, vec![param(0), param(0), param(0)], param(0)) + } + "simd_gather" => { + (3, vec![param(0), param(1), param(2)], param(0)) + } + "simd_scatter" => { + (3, vec![param(0), param(1), param(2)], tcx.mk_nil()) + } "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)), "simd_cast" => (2, vec![param(0)], param(1)), diff --git a/src/test/codegen/simd-intrinsic-float-abs.rs b/src/test/codegen/simd-intrinsic-float-abs.rs new file mode 100644 index 00000000000..8fc6b7a4826 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-abs.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fabs(x: T) -> T; +} + +// CHECK-LABEL: @fabs_32x2 +#[no_mangle] +pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.fabs.v2f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x4 +#[no_mangle] +pub unsafe fn fabs_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.fabs.v4f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x8 +#[no_mangle] +pub unsafe fn fabs_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.fabs.v8f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x16 +#[no_mangle] +pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.fabs.v16f32 + simd_fabs(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fabs_64x4 +#[no_mangle] +pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.fabs.v4f64 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_64x2 +#[no_mangle] +pub unsafe fn fabs_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.fabs.v2f64 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_64x8 +#[no_mangle] +pub unsafe fn fabs_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.fabs.v8f64 + simd_fabs(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-ceil.rs b/src/test/codegen/simd-intrinsic-float-ceil.rs new file mode 100644 index 00000000000..aca591b97ab --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-ceil.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_ceil(x: T) -> T; +} + +// CHECK-LABEL: @ceil_32x2 +#[no_mangle] +pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.ceil.v2f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x4 +#[no_mangle] +pub unsafe fn ceil_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.ceil.v4f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x8 +#[no_mangle] +pub unsafe fn ceil_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.ceil.v8f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x16 +#[no_mangle] +pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.ceil.v16f32 + simd_ceil(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @ceil_64x4 +#[no_mangle] +pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.ceil.v4f64 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_64x2 +#[no_mangle] +pub unsafe fn ceil_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.ceil.v2f64 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_64x8 +#[no_mangle] +pub unsafe fn ceil_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.ceil.v8f64 + simd_ceil(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-cos.rs b/src/test/codegen/simd-intrinsic-float-cos.rs new file mode 100644 index 00000000000..77715f23d63 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-cos.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fcos(x: T) -> T; +} + +// CHECK-LABEL: @fcos_32x2 +#[no_mangle] +pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.cos.v2f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x4 +#[no_mangle] +pub unsafe fn fcos_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.cos.v4f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x8 +#[no_mangle] +pub unsafe fn fcos_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.cos.v8f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x16 +#[no_mangle] +pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.cos.v16f32 + simd_fcos(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fcos_64x4 +#[no_mangle] +pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.cos.v4f64 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_64x2 +#[no_mangle] +pub unsafe fn fcos_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.cos.v2f64 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_64x8 +#[no_mangle] +pub unsafe fn fcos_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.cos.v8f64 + simd_fcos(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-exp.rs b/src/test/codegen/simd-intrinsic-float-exp.rs new file mode 100644 index 00000000000..0046ce66860 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-exp.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fexp(x: T) -> T; +} + +// CHECK-LABEL: @exp_32x2 +#[no_mangle] +pub unsafe fn exp_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.exp.v2f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x4 +#[no_mangle] +pub unsafe fn exp_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.exp.v4f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x8 +#[no_mangle] +pub unsafe fn exp_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.exp.v8f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x16 +#[no_mangle] +pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.exp.v16f32 + simd_fexp(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @exp_64x4 +#[no_mangle] +pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.exp.v4f64 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_64x2 +#[no_mangle] +pub unsafe fn exp_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.exp.v2f64 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_64x8 +#[no_mangle] +pub unsafe fn exp_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.exp.v8f64 + simd_fexp(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-exp2.rs b/src/test/codegen/simd-intrinsic-float-exp2.rs new file mode 100644 index 00000000000..a93fd7ea65a --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-exp2.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fexp2(x: T) -> T; +} + +// CHECK-LABEL: @exp2_32x2 +#[no_mangle] +pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.exp2.v2f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x4 +#[no_mangle] +pub unsafe fn exp2_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.exp2.v4f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x8 +#[no_mangle] +pub unsafe fn exp2_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.exp2.v8f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x16 +#[no_mangle] +pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.exp2.v16f32 + simd_fexp2(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @exp2_64x4 +#[no_mangle] +pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.exp2.v4f64 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_64x2 +#[no_mangle] +pub unsafe fn exp2_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.exp2.v2f64 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_64x8 +#[no_mangle] +pub unsafe fn exp2_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.exp2.v8f64 + simd_fexp2(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-floor.rs b/src/test/codegen/simd-intrinsic-float-floor.rs new file mode 100644 index 00000000000..dfea41869de --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-floor.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_floor(x: T) -> T; +} + +// CHECK-LABEL: @floor_32x2 +#[no_mangle] +pub unsafe fn floor_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.floor.v2f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x4 +#[no_mangle] +pub unsafe fn floor_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.floor.v4f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x8 +#[no_mangle] +pub unsafe fn floor_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.floor.v8f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x16 +#[no_mangle] +pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.floor.v16f32 + simd_floor(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @floor_64x4 +#[no_mangle] +pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.floor.v4f64 + simd_floor(a) +} + +// CHECK-LABEL: @floor_64x2 +#[no_mangle] +pub unsafe fn floor_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.floor.v2f64 + simd_floor(a) +} + +// CHECK-LABEL: @floor_64x8 +#[no_mangle] +pub unsafe fn floor_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.floor.v8f64 + simd_floor(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-fma.rs b/src/test/codegen/simd-intrinsic-float-fma.rs new file mode 100644 index 00000000000..02f6d0ff75e --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-fma.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fma(x: T, b: T, c: T) -> T; +} + +// CHECK-LABEL: @fma_32x2 +#[no_mangle] +pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.fma.v2f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x4 +#[no_mangle] +pub unsafe fn fma_32x4(a: f32x4, b: f32x4, c: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.fma.v4f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x8 +#[no_mangle] +pub unsafe fn fma_32x8(a: f32x8, b: f32x8, c: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.fma.v8f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x16 +#[no_mangle] +pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.fma.v16f32 + simd_fma(a, b, c) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fma_64x4 +#[no_mangle] +pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.fma.v4f64 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_64x2 +#[no_mangle] +pub unsafe fn fma_64x2(a: f64x2, b: f64x2, c: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.fma.v2f64 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_64x8 +#[no_mangle] +pub unsafe fn fma_64x8(a: f64x8, b: f64x8, c: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.fma.v8f64 + simd_fma(a, b, c) +} diff --git a/src/test/codegen/simd-intrinsic-float-fsqrt.rs b/src/test/codegen/simd-intrinsic-float-fsqrt.rs new file mode 100644 index 00000000000..d8fc3e3675b --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-fsqrt.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fsqrt(x: T) -> T; +} + +// CHECK-LABEL: @fsqrt_32x2 +#[no_mangle] +pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.sqrt.v2f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x4 +#[no_mangle] +pub unsafe fn fsqrt_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.sqrt.v4f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x8 +#[no_mangle] +pub unsafe fn fsqrt_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.sqrt.v8f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x16 +#[no_mangle] +pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.sqrt.v16f32 + simd_fsqrt(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fsqrt_64x4 +#[no_mangle] +pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.sqrt.v4f64 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_64x2 +#[no_mangle] +pub unsafe fn fsqrt_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.sqrt.v2f64 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_64x8 +#[no_mangle] +pub unsafe fn fsqrt_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.sqrt.v8f64 + simd_fsqrt(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-log10.rs b/src/test/codegen/simd-intrinsic-float-log10.rs new file mode 100644 index 00000000000..0e094ac5b6e --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-log10.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_flog10(x: T) -> T; +} + +// CHECK-LABEL: @log10_32x2 +#[no_mangle] +pub unsafe fn log10_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log10.v2f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x4 +#[no_mangle] +pub unsafe fn log10_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log10.v4f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x8 +#[no_mangle] +pub unsafe fn log10_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log10.v8f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x16 +#[no_mangle] +pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log10.v16f32 + simd_flog10(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @log10_64x4 +#[no_mangle] +pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log10.v4f64 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_64x2 +#[no_mangle] +pub unsafe fn log10_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log10.v2f64 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_64x8 +#[no_mangle] +pub unsafe fn log10_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log10.v8f64 + simd_flog10(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-log2.rs b/src/test/codegen/simd-intrinsic-float-log2.rs new file mode 100644 index 00000000000..da1207fc7ee --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-log2.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_flog2(x: T) -> T; +} + +// CHECK-LABEL: @log2_32x2 +#[no_mangle] +pub unsafe fn log2_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log2.v2f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x4 +#[no_mangle] +pub unsafe fn log2_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log2.v4f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x8 +#[no_mangle] +pub unsafe fn log2_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log2.v8f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x16 +#[no_mangle] +pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log2.v16f32 + simd_flog2(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @log2_64x4 +#[no_mangle] +pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log2.v4f64 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_64x2 +#[no_mangle] +pub unsafe fn log2_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log2.v2f64 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_64x8 +#[no_mangle] +pub unsafe fn log2_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log2.v8f64 + simd_flog2(a) +} diff --git a/src/test/codegen/simd-intrinsic-float-pow.rs b/src/test/codegen/simd-intrinsic-float-pow.rs new file mode 100644 index 00000000000..5817dd49f4d --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-pow.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fpow(x: T, b: T) -> T; +} + +// CHECK-LABEL: @fpow_32x2 +#[no_mangle] +pub unsafe fn fpow_32x2(a: f32x2, b: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.pow.v2f32 + simd_fpow(a, b) +} + +// CHECK-LABEL: @fpow_32x4 +#[no_mangle] +pub unsafe fn fpow_32x4(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.pow.v4f32 + simd_fpow(a, b) +} + +// CHECK-LABEL: @fpow_32x8 +#[no_mangle] +pub unsafe fn fpow_32x8(a: f32x8, b: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.pow.v8f32 + simd_fpow(a, b) +} + +// CHECK-LABEL: @fpow_32x16 +#[no_mangle] +pub unsafe fn fpow_32x16(a: f32x16, b: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.pow.v16f32 + simd_fpow(a, b) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fpow_64x4 +#[no_mangle] +pub unsafe fn fpow_64x4(a: f64x4, b: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.pow.v4f64 + simd_fpow(a, b) +} + +// CHECK-LABEL: @fpow_64x2 +#[no_mangle] +pub unsafe fn fpow_64x2(a: f64x2, b: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.pow.v2f64 + simd_fpow(a, b) +} + +// CHECK-LABEL: @fpow_64x8 +#[no_mangle] +pub unsafe fn fpow_64x8(a: f64x8, b: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.pow.v8f64 + simd_fpow(a, b) +} diff --git a/src/test/codegen/simd-intrinsic-float-powi.rs b/src/test/codegen/simd-intrinsic-float-powi.rs new file mode 100644 index 00000000000..2db5689f623 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-powi.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fpowi(x: T, b: i32) -> T; +} + +// CHECK-LABEL: @fpowi_32x2 +#[no_mangle] +pub unsafe fn fpowi_32x2(a: f32x2, b: i32) -> f32x2 { + // CHECK: call <2 x float> @llvm.powi.v2f32 + simd_fpowi(a, b) +} + +// CHECK-LABEL: @fpowi_32x4 +#[no_mangle] +pub unsafe fn fpowi_32x4(a: f32x4, b: i32) -> f32x4 { + // CHECK: call <4 x float> @llvm.powi.v4f32 + simd_fpowi(a, b) +} + +// CHECK-LABEL: @fpowi_32x8 +#[no_mangle] +pub unsafe fn fpowi_32x8(a: f32x8, b: i32) -> f32x8 { + // CHECK: call <8 x float> @llvm.powi.v8f32 + simd_fpowi(a, b) +} + +// CHECK-LABEL: @fpowi_32x16 +#[no_mangle] +pub unsafe fn fpowi_32x16(a: f32x16, b: i32) -> f32x16 { + // CHECK: call <16 x float> @llvm.powi.v16f32 + simd_fpowi(a, b) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fpowi_64x4 +#[no_mangle] +pub unsafe fn fpowi_64x4(a: f64x4, b: i32) -> f64x4 { + // CHECK: call <4 x double> @llvm.powi.v4f64 + simd_fpowi(a, b) +} + +// CHECK-LABEL: @fpowi_64x2 +#[no_mangle] +pub unsafe fn fpowi_64x2(a: f64x2, b: i32) -> f64x2 { + // CHECK: call <2 x double> @llvm.powi.v2f64 + simd_fpowi(a, b) +} + +// CHECK-LABEL: @fpowi_64x8 +#[no_mangle] +pub unsafe fn fpowi_64x8(a: f64x8, b: i32) -> f64x8 { + // CHECK: call <8 x double> @llvm.powi.v8f64 + simd_fpowi(a, b) +} diff --git a/src/test/codegen/simd-intrinsic-float-sin.rs b/src/test/codegen/simd-intrinsic-float-sin.rs new file mode 100644 index 00000000000..15720462db7 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-sin.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fsin(x: T) -> T; +} + +// CHECK-LABEL: @fsin_32x2 +#[no_mangle] +pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.sin.v2f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x4 +#[no_mangle] +pub unsafe fn fsin_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.sin.v4f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x8 +#[no_mangle] +pub unsafe fn fsin_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.sin.v8f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x16 +#[no_mangle] +pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.sin.v16f32 + simd_fsin(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @fsin_64x4 +#[no_mangle] +pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.sin.v4f64 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_64x2 +#[no_mangle] +pub unsafe fn fsin_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.sin.v2f64 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_64x8 +#[no_mangle] +pub unsafe fn fsin_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.sin.v8f64 + simd_fsin(a) +} diff --git a/src/test/codegen/simd-intrinsic-generic-gather.rs b/src/test/codegen/simd-intrinsic-generic-gather.rs new file mode 100644 index 00000000000..58876d21978 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-generic-gather.rs @@ -0,0 +1,46 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Vec2(pub T, pub T); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Vec4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(value: T, pointers: P, mask: M) -> T; +} + +// CHECK-LABEL: @gather_f32x2 +#[no_mangle] +pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2, + values: Vec2) -> Vec2 { + // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0f32(<2 x float*> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x float> {{.*}}) + simd_gather(values, pointers, mask) +} + +// CHECK-LABEL: @gather_pf32x2 +#[no_mangle] +pub unsafe fn gather_pf32x2(pointers: Vec2<*const *const f32>, mask: Vec2, + values: Vec2<*const f32>) -> Vec2<*const f32> { + // CHECK: call <2 x float*> @llvm.masked.gather.v2p0f32.v2p0p0f32(<2 x float**> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x float*> {{.*}}) + simd_gather(values, pointers, mask) +} diff --git a/src/test/codegen/simd-intrinsic-generic-scatter.rs b/src/test/codegen/simd-intrinsic-generic-scatter.rs new file mode 100644 index 00000000000..44bb4b71259 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-generic-scatter.rs @@ -0,0 +1,46 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Vec2(pub T, pub T); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Vec4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_scatter(value: T, pointers: P, mask: M); +} + +// CHECK-LABEL: @scatter_f32x2 +#[no_mangle] +pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2, + values: Vec2) { + // CHECK: call void @llvm.masked.scatter.v2f32.v2p0f32(<2 x float> {{.*}}, <2 x float*> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}) + simd_scatter(values, pointers, mask) +} + +// CHECK-LABEL: @scatter_pf32x2 +#[no_mangle] +pub unsafe fn scatter_pf32x2(pointers: Vec2<*mut *const f32>, mask: Vec2, + values: Vec2<*const f32>) { + // CHECK: call void @llvm.masked.scatter.v2p0f32.v2p0p0f32(<2 x float*> {{.*}}, <2 x float**> {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}) + simd_scatter(values, pointers, mask) +} -- cgit 1.4.1-3-g733a5 From 7a6a23d818a288d11a3131b247d7d88a6d318db8 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 8 May 2018 16:16:26 +0200 Subject: fix tidy --- src/librustc_codegen_llvm/intrinsic.rs | 22 ++++++++++++++++------ src/test/codegen/simd-intrinsic-generic-gather.rs | 1 + src/test/codegen/simd-intrinsic-generic-scatter.rs | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 71641a7f248..a2faaeec789 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1140,8 +1140,12 @@ fn generic_simd_intrinsic<'a, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } - fn simd_simple_float_intrinsic<'a, 'tcx>(name: &str, in_elem: &::rustc::ty::TyS, in_ty: &::rustc::ty::TyS, - in_len: usize, bx: &Builder<'a, 'tcx>, span: Span, + fn simd_simple_float_intrinsic<'a, 'tcx>(name: &str, + in_elem: &::rustc::ty::TyS, + in_ty: &::rustc::ty::TyS, + in_len: usize, + bx: &Builder<'a, 'tcx>, + span: Span, args: &[OperandRef<'tcx>]) -> Result { macro_rules! emit_error { @@ -1167,14 +1171,17 @@ fn generic_simd_intrinsic<'a, 'tcx>( let ety = match in_elem.sty { ty::TyFloat(f) if f.bit_width() == 32 => { if in_len < 2 || in_len > 16 { - return_error!("unsupported floating-point vector `{}` with length `{}` out-of-range [2, 16]", - in_ty, in_len); + return_error!( + "unsupported floating-point vector `{}` with length `{}` \ + out-of-range [2, 16]", + in_ty, in_len); } "f32" }, ty::TyFloat(f) if f.bit_width() == 64 => { if in_len < 2 || in_len > 8 { - return_error!("unsupported floating-point vector `{}` with length `{}` out-of-range [2, 8]", + return_error!("unsupported floating-point vector `{}` with length `{}` \ + out-of-range [2, 8]", in_ty, in_len); } "f64" @@ -1504,7 +1511,10 @@ fn generic_simd_intrinsic<'a, 'tcx>( let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); let f = declare::declare_cfn(bx.cx, &llvm_intrinsic, - Type::func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], &ret_t)); + Type::func(&[llvm_elem_vec_ty, + llvm_pointer_vec_ty, + alignment_ty, + mask_ty], &ret_t)); llvm::SetUnnamedAddr(f, false); let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None); diff --git a/src/test/codegen/simd-intrinsic-generic-gather.rs b/src/test/codegen/simd-intrinsic-generic-gather.rs index 58876d21978..605a952e8ff 100644 --- a/src/test/codegen/simd-intrinsic-generic-gather.rs +++ b/src/test/codegen/simd-intrinsic-generic-gather.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-emscripten +// ignore-tidy-linelength // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/simd-intrinsic-generic-scatter.rs b/src/test/codegen/simd-intrinsic-generic-scatter.rs index 44bb4b71259..752265412f0 100644 --- a/src/test/codegen/simd-intrinsic-generic-scatter.rs +++ b/src/test/codegen/simd-intrinsic-generic-scatter.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-emscripten +// ignore-tidy-linelength // compile-flags: -C no-prepopulate-passes -- cgit 1.4.1-3-g733a5 From 2809b0155af72fd9e6c5c3d27942dd95b6718ef7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 9 May 2018 16:01:52 +0200 Subject: add run-time test and missing codegen test --- src/test/codegen/simd-intrinsic-float-log.rs | 104 +++++++++++++++++++++++++ src/test/run-pass/simd-intrinsic-float-math.rs | 90 +++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 src/test/codegen/simd-intrinsic-float-log.rs create mode 100644 src/test/run-pass/simd-intrinsic-float-math.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-float-log.rs b/src/test/codegen/simd-intrinsic-float-log.rs new file mode 100644 index 00000000000..dd77294c824 --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-log.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x2(pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x8(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x16(pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32, + pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_flog(x: T) -> T; +} + +// CHECK-LABEL: @log_32x2 +#[no_mangle] +pub unsafe fn log_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log.v2f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x4 +#[no_mangle] +pub unsafe fn log_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log.v4f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x8 +#[no_mangle] +pub unsafe fn log_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log.v8f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x16 +#[no_mangle] +pub unsafe fn log_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log.v16f32 + simd_flog(a) +} + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x2(pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x4(pub f64, pub f64, pub f64, pub f64); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f64x8(pub f64, pub f64, pub f64, pub f64, + pub f64, pub f64, pub f64, pub f64); + +// CHECK-LABEL: @log_64x4 +#[no_mangle] +pub unsafe fn log_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log.v4f64 + simd_flog(a) +} + +// CHECK-LABEL: @log_64x2 +#[no_mangle] +pub unsafe fn log_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log.v2f64 + simd_flog(a) +} + +// CHECK-LABEL: @log_64x8 +#[no_mangle] +pub unsafe fn log_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log.v8f64 + simd_flog(a) +} diff --git a/src/test/run-pass/simd-intrinsic-float-math.rs b/src/test/run-pass/simd-intrinsic-float-math.rs new file mode 100644 index 00000000000..e2bf310641c --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-float-math.rs @@ -0,0 +1,90 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten +// error-pattern: panicked + +// Test that the simd floating-point math intrinsics produce correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fsqrt(x: T) -> T; + fn simd_fabs(x: T) -> T; + fn simd_fsin(x: T) -> T; + fn simd_fcos(x: T) -> T; + fn simd_ceil(x: T) -> T; + fn simd_fexp(x: T) -> T; + fn simd_fexp2(x: T) -> T; + fn simd_floor(x: T) -> T; + fn simd_fma(x: T, y: T, z: T) -> T; + fn simd_flog(x: T) -> T; + fn simd_flog10(x: T) -> T; + fn simd_flog2(x: T) -> T; + fn simd_fpow(x: T, y: T) -> T; + fn simd_fpowi(x: T, y: i32) -> T; +} + +fn main() { + let x = f32x4(1.0, 1.0, 1.0, 1.0); + let y = f32x4(-1.0, -1.0, -1.0, -1.0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + let h = f32x4(0.5, 0.5, 0.5, 0.5); + + unsafe { + let r = simd_fabs(y); + assert_eq!(x, r); + + let r = simd_fcos(z); + assert_eq!(x, r); + + let r = simd_ceil(h); + assert_eq!(x, r); + + let r = simd_fexp(z); + assert_eq!(x, r); + + let r = simd_fexp2(z); + assert_eq!(x, r); + + let r = simd_floor(h); + assert_eq!(z, r); + + let r = simd_fma(x, h, h); + assert_eq!(x, r); + + let r = simd_fsqrt(x); + assert_eq!(x, r); + + let r = simd_flog(x); + assert_eq!(z, r); + + let r = simd_flog2(x); + assert_eq!(z, r); + + let r = simd_flog10(x); + assert_eq!(z, r); + + let r = simd_fpow(h, x); + assert_eq!(h, r); + + let r = simd_fpowi(h, 1); + assert_eq!(h, r); + + let r = simd_fsin(z); + assert_eq!(z, r); + } +} -- cgit 1.4.1-3-g733a5 From 1ffc30a45976374e914df250e2852821eb811f41 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 9 May 2018 16:47:38 +0200 Subject: add gather/scatter run-time test --- src/test/codegen/simd-intrinsic-generic-gather.rs | 1 + src/test/codegen/simd-intrinsic-generic-scatter.rs | 2 + src/test/run-pass/simd-intrinsic-generic-gather.rs | 80 ++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/test/run-pass/simd-intrinsic-generic-gather.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/simd-intrinsic-generic-gather.rs b/src/test/codegen/simd-intrinsic-generic-gather.rs index 605a952e8ff..6c47bf3e321 100644 --- a/src/test/codegen/simd-intrinsic-generic-gather.rs +++ b/src/test/codegen/simd-intrinsic-generic-gather.rs @@ -10,6 +10,7 @@ // ignore-emscripten // ignore-tidy-linelength +// min-llvm-version 6.0 // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/simd-intrinsic-generic-scatter.rs b/src/test/codegen/simd-intrinsic-generic-scatter.rs index 752265412f0..7b5b2e55e29 100644 --- a/src/test/codegen/simd-intrinsic-generic-scatter.rs +++ b/src/test/codegen/simd-intrinsic-generic-scatter.rs @@ -10,6 +10,7 @@ // ignore-emscripten // ignore-tidy-linelength +// min-llvm-version 6.0 // compile-flags: -C no-prepopulate-passes @@ -38,6 +39,7 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2, simd_scatter(values, pointers, mask) } + // CHECK-LABEL: @scatter_pf32x2 #[no_mangle] pub unsafe fn scatter_pf32x2(pointers: Vec2<*mut *const f32>, mask: Vec2, diff --git a/src/test/run-pass/simd-intrinsic-generic-gather.rs b/src/test/run-pass/simd-intrinsic-generic-gather.rs new file mode 100644 index 00000000000..dbc5221441f --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-gather.rs @@ -0,0 +1,80 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten +// min-llvm-version 6.0 + +// Test that the simd_{gather,scatter} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; + fn simd_scatter(x: T, y: U, z: V) -> (); +} + +fn main() { + let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; + + let default = x4(-3_f32, -3., -3., -3.); + let s_strided = x4(0_f32, 2., -3., 6.); + let mask = x4(-1_i32, -1, 0, -1); + + // reading from *const + unsafe { + let pointer = &x[0] as *const f32; + let pointers = x4( + pointer.offset(0) as *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let values = x4(42_f32, 43_f32, 44_f32, 45_f32); + simd_scatter(values, pointers, mask); + + assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); + } +} -- cgit 1.4.1-3-g733a5 From 1bd9573c1fb4753272254871c5a33d87328585bd Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 14 May 2018 12:03:04 +0200 Subject: enable fast-math flags --- src/librustc_codegen_llvm/intrinsic.rs | 8 +++++--- src/test/codegen/simd-intrinsic-float-abs.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-ceil.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-cos.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-exp.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-exp2.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-floor.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-fma.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-fsqrt.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-log.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-log10.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-log2.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-pow.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-powi.rs | 14 +++++++------- src/test/codegen/simd-intrinsic-float-sin.rs | 14 +++++++------- 15 files changed, 103 insertions(+), 101 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index a2faaeec789..18f940800d3 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1197,9 +1197,11 @@ fn generic_simd_intrinsic<'a, 'tcx>( let llvm_name = &format!("llvm.{0}.v{1}{2}", name, in_len, ety); let intrinsic = bx.cx.get_intrinsic(&llvm_name); - return Ok(bx.call(intrinsic, - &args.iter().map(|arg| arg.immediate()).collect::>(), - None)); + let c = bx.call(intrinsic, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None); + unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) }; + return Ok(c); } if name == "simd_fsqrt" { diff --git a/src/test/codegen/simd-intrinsic-float-abs.rs b/src/test/codegen/simd-intrinsic-float-abs.rs index 8fc6b7a4826..49f1f3e8565 100644 --- a/src/test/codegen/simd-intrinsic-float-abs.rs +++ b/src/test/codegen/simd-intrinsic-float-abs.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fabs_32x2 #[no_mangle] pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.fabs.v2f32 + // CHECK: call fast <2 x float> @llvm.fabs.v2f32 simd_fabs(a) } // CHECK-LABEL: @fabs_32x4 #[no_mangle] pub unsafe fn fabs_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.fabs.v4f32 + // CHECK: call fast <4 x float> @llvm.fabs.v4f32 simd_fabs(a) } // CHECK-LABEL: @fabs_32x8 #[no_mangle] pub unsafe fn fabs_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.fabs.v8f32 + // CHECK: call fast <8 x float> @llvm.fabs.v8f32 simd_fabs(a) } // CHECK-LABEL: @fabs_32x16 #[no_mangle] pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.fabs.v16f32 + // CHECK: call fast <16 x float> @llvm.fabs.v16f32 simd_fabs(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fabs_64x4 #[no_mangle] pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.fabs.v4f64 + // CHECK: call fast <4 x double> @llvm.fabs.v4f64 simd_fabs(a) } // CHECK-LABEL: @fabs_64x2 #[no_mangle] pub unsafe fn fabs_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.fabs.v2f64 + // CHECK: call fast <2 x double> @llvm.fabs.v2f64 simd_fabs(a) } // CHECK-LABEL: @fabs_64x8 #[no_mangle] pub unsafe fn fabs_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.fabs.v8f64 + // CHECK: call fast <8 x double> @llvm.fabs.v8f64 simd_fabs(a) } diff --git a/src/test/codegen/simd-intrinsic-float-ceil.rs b/src/test/codegen/simd-intrinsic-float-ceil.rs index aca591b97ab..4a6f162e16b 100644 --- a/src/test/codegen/simd-intrinsic-float-ceil.rs +++ b/src/test/codegen/simd-intrinsic-float-ceil.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @ceil_32x2 #[no_mangle] pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.ceil.v2f32 + // CHECK: call fast <2 x float> @llvm.ceil.v2f32 simd_ceil(a) } // CHECK-LABEL: @ceil_32x4 #[no_mangle] pub unsafe fn ceil_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.ceil.v4f32 + // CHECK: call fast <4 x float> @llvm.ceil.v4f32 simd_ceil(a) } // CHECK-LABEL: @ceil_32x8 #[no_mangle] pub unsafe fn ceil_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.ceil.v8f32 + // CHECK: call fast <8 x float> @llvm.ceil.v8f32 simd_ceil(a) } // CHECK-LABEL: @ceil_32x16 #[no_mangle] pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.ceil.v16f32 + // CHECK: call fast <16 x float> @llvm.ceil.v16f32 simd_ceil(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @ceil_64x4 #[no_mangle] pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.ceil.v4f64 + // CHECK: call fast <4 x double> @llvm.ceil.v4f64 simd_ceil(a) } // CHECK-LABEL: @ceil_64x2 #[no_mangle] pub unsafe fn ceil_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.ceil.v2f64 + // CHECK: call fast <2 x double> @llvm.ceil.v2f64 simd_ceil(a) } // CHECK-LABEL: @ceil_64x8 #[no_mangle] pub unsafe fn ceil_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.ceil.v8f64 + // CHECK: call fast <8 x double> @llvm.ceil.v8f64 simd_ceil(a) } diff --git a/src/test/codegen/simd-intrinsic-float-cos.rs b/src/test/codegen/simd-intrinsic-float-cos.rs index 77715f23d63..6304c6c644f 100644 --- a/src/test/codegen/simd-intrinsic-float-cos.rs +++ b/src/test/codegen/simd-intrinsic-float-cos.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fcos_32x2 #[no_mangle] pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.cos.v2f32 + // CHECK: call fast <2 x float> @llvm.cos.v2f32 simd_fcos(a) } // CHECK-LABEL: @fcos_32x4 #[no_mangle] pub unsafe fn fcos_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.cos.v4f32 + // CHECK: call fast <4 x float> @llvm.cos.v4f32 simd_fcos(a) } // CHECK-LABEL: @fcos_32x8 #[no_mangle] pub unsafe fn fcos_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.cos.v8f32 + // CHECK: call fast <8 x float> @llvm.cos.v8f32 simd_fcos(a) } // CHECK-LABEL: @fcos_32x16 #[no_mangle] pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.cos.v16f32 + // CHECK: call fast <16 x float> @llvm.cos.v16f32 simd_fcos(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fcos_64x4 #[no_mangle] pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.cos.v4f64 + // CHECK: call fast <4 x double> @llvm.cos.v4f64 simd_fcos(a) } // CHECK-LABEL: @fcos_64x2 #[no_mangle] pub unsafe fn fcos_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.cos.v2f64 + // CHECK: call fast <2 x double> @llvm.cos.v2f64 simd_fcos(a) } // CHECK-LABEL: @fcos_64x8 #[no_mangle] pub unsafe fn fcos_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.cos.v8f64 + // CHECK: call fast <8 x double> @llvm.cos.v8f64 simd_fcos(a) } diff --git a/src/test/codegen/simd-intrinsic-float-exp.rs b/src/test/codegen/simd-intrinsic-float-exp.rs index 0046ce66860..110031c6451 100644 --- a/src/test/codegen/simd-intrinsic-float-exp.rs +++ b/src/test/codegen/simd-intrinsic-float-exp.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @exp_32x2 #[no_mangle] pub unsafe fn exp_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.exp.v2f32 + // CHECK: call fast <2 x float> @llvm.exp.v2f32 simd_fexp(a) } // CHECK-LABEL: @exp_32x4 #[no_mangle] pub unsafe fn exp_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.exp.v4f32 + // CHECK: call fast <4 x float> @llvm.exp.v4f32 simd_fexp(a) } // CHECK-LABEL: @exp_32x8 #[no_mangle] pub unsafe fn exp_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.exp.v8f32 + // CHECK: call fast <8 x float> @llvm.exp.v8f32 simd_fexp(a) } // CHECK-LABEL: @exp_32x16 #[no_mangle] pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.exp.v16f32 + // CHECK: call fast <16 x float> @llvm.exp.v16f32 simd_fexp(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @exp_64x4 #[no_mangle] pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.exp.v4f64 + // CHECK: call fast <4 x double> @llvm.exp.v4f64 simd_fexp(a) } // CHECK-LABEL: @exp_64x2 #[no_mangle] pub unsafe fn exp_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.exp.v2f64 + // CHECK: call fast <2 x double> @llvm.exp.v2f64 simd_fexp(a) } // CHECK-LABEL: @exp_64x8 #[no_mangle] pub unsafe fn exp_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.exp.v8f64 + // CHECK: call fast <8 x double> @llvm.exp.v8f64 simd_fexp(a) } diff --git a/src/test/codegen/simd-intrinsic-float-exp2.rs b/src/test/codegen/simd-intrinsic-float-exp2.rs index a93fd7ea65a..dc62c90822f 100644 --- a/src/test/codegen/simd-intrinsic-float-exp2.rs +++ b/src/test/codegen/simd-intrinsic-float-exp2.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @exp2_32x2 #[no_mangle] pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.exp2.v2f32 + // CHECK: call fast <2 x float> @llvm.exp2.v2f32 simd_fexp2(a) } // CHECK-LABEL: @exp2_32x4 #[no_mangle] pub unsafe fn exp2_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.exp2.v4f32 + // CHECK: call fast <4 x float> @llvm.exp2.v4f32 simd_fexp2(a) } // CHECK-LABEL: @exp2_32x8 #[no_mangle] pub unsafe fn exp2_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.exp2.v8f32 + // CHECK: call fast <8 x float> @llvm.exp2.v8f32 simd_fexp2(a) } // CHECK-LABEL: @exp2_32x16 #[no_mangle] pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.exp2.v16f32 + // CHECK: call fast <16 x float> @llvm.exp2.v16f32 simd_fexp2(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @exp2_64x4 #[no_mangle] pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.exp2.v4f64 + // CHECK: call fast <4 x double> @llvm.exp2.v4f64 simd_fexp2(a) } // CHECK-LABEL: @exp2_64x2 #[no_mangle] pub unsafe fn exp2_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.exp2.v2f64 + // CHECK: call fast <2 x double> @llvm.exp2.v2f64 simd_fexp2(a) } // CHECK-LABEL: @exp2_64x8 #[no_mangle] pub unsafe fn exp2_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.exp2.v8f64 + // CHECK: call fast <8 x double> @llvm.exp2.v8f64 simd_fexp2(a) } diff --git a/src/test/codegen/simd-intrinsic-float-floor.rs b/src/test/codegen/simd-intrinsic-float-floor.rs index dfea41869de..9bc8ca0d152 100644 --- a/src/test/codegen/simd-intrinsic-float-floor.rs +++ b/src/test/codegen/simd-intrinsic-float-floor.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @floor_32x2 #[no_mangle] pub unsafe fn floor_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.floor.v2f32 + // CHECK: call fast <2 x float> @llvm.floor.v2f32 simd_floor(a) } // CHECK-LABEL: @floor_32x4 #[no_mangle] pub unsafe fn floor_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.floor.v4f32 + // CHECK: call fast <4 x float> @llvm.floor.v4f32 simd_floor(a) } // CHECK-LABEL: @floor_32x8 #[no_mangle] pub unsafe fn floor_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.floor.v8f32 + // CHECK: call fast <8 x float> @llvm.floor.v8f32 simd_floor(a) } // CHECK-LABEL: @floor_32x16 #[no_mangle] pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.floor.v16f32 + // CHECK: call fast <16 x float> @llvm.floor.v16f32 simd_floor(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @floor_64x4 #[no_mangle] pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.floor.v4f64 + // CHECK: call fast <4 x double> @llvm.floor.v4f64 simd_floor(a) } // CHECK-LABEL: @floor_64x2 #[no_mangle] pub unsafe fn floor_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.floor.v2f64 + // CHECK: call fast <2 x double> @llvm.floor.v2f64 simd_floor(a) } // CHECK-LABEL: @floor_64x8 #[no_mangle] pub unsafe fn floor_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.floor.v8f64 + // CHECK: call fast <8 x double> @llvm.floor.v8f64 simd_floor(a) } diff --git a/src/test/codegen/simd-intrinsic-float-fma.rs b/src/test/codegen/simd-intrinsic-float-fma.rs index 02f6d0ff75e..acd7f717214 100644 --- a/src/test/codegen/simd-intrinsic-float-fma.rs +++ b/src/test/codegen/simd-intrinsic-float-fma.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fma_32x2 #[no_mangle] pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.fma.v2f32 + // CHECK: call fast <2 x float> @llvm.fma.v2f32 simd_fma(a, b, c) } // CHECK-LABEL: @fma_32x4 #[no_mangle] pub unsafe fn fma_32x4(a: f32x4, b: f32x4, c: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.fma.v4f32 + // CHECK: call fast <4 x float> @llvm.fma.v4f32 simd_fma(a, b, c) } // CHECK-LABEL: @fma_32x8 #[no_mangle] pub unsafe fn fma_32x8(a: f32x8, b: f32x8, c: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.fma.v8f32 + // CHECK: call fast <8 x float> @llvm.fma.v8f32 simd_fma(a, b, c) } // CHECK-LABEL: @fma_32x16 #[no_mangle] pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.fma.v16f32 + // CHECK: call fast <16 x float> @llvm.fma.v16f32 simd_fma(a, b, c) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fma_64x4 #[no_mangle] pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.fma.v4f64 + // CHECK: call fast <4 x double> @llvm.fma.v4f64 simd_fma(a, b, c) } // CHECK-LABEL: @fma_64x2 #[no_mangle] pub unsafe fn fma_64x2(a: f64x2, b: f64x2, c: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.fma.v2f64 + // CHECK: call fast <2 x double> @llvm.fma.v2f64 simd_fma(a, b, c) } // CHECK-LABEL: @fma_64x8 #[no_mangle] pub unsafe fn fma_64x8(a: f64x8, b: f64x8, c: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.fma.v8f64 + // CHECK: call fast <8 x double> @llvm.fma.v8f64 simd_fma(a, b, c) } diff --git a/src/test/codegen/simd-intrinsic-float-fsqrt.rs b/src/test/codegen/simd-intrinsic-float-fsqrt.rs index d8fc3e3675b..2bad0bba48a 100644 --- a/src/test/codegen/simd-intrinsic-float-fsqrt.rs +++ b/src/test/codegen/simd-intrinsic-float-fsqrt.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fsqrt_32x2 #[no_mangle] pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.sqrt.v2f32 + // CHECK: call fast <2 x float> @llvm.sqrt.v2f32 simd_fsqrt(a) } // CHECK-LABEL: @fsqrt_32x4 #[no_mangle] pub unsafe fn fsqrt_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.sqrt.v4f32 + // CHECK: call fast <4 x float> @llvm.sqrt.v4f32 simd_fsqrt(a) } // CHECK-LABEL: @fsqrt_32x8 #[no_mangle] pub unsafe fn fsqrt_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.sqrt.v8f32 + // CHECK: call fast <8 x float> @llvm.sqrt.v8f32 simd_fsqrt(a) } // CHECK-LABEL: @fsqrt_32x16 #[no_mangle] pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.sqrt.v16f32 + // CHECK: call fast <16 x float> @llvm.sqrt.v16f32 simd_fsqrt(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fsqrt_64x4 #[no_mangle] pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.sqrt.v4f64 + // CHECK: call fast <4 x double> @llvm.sqrt.v4f64 simd_fsqrt(a) } // CHECK-LABEL: @fsqrt_64x2 #[no_mangle] pub unsafe fn fsqrt_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.sqrt.v2f64 + // CHECK: call fast <2 x double> @llvm.sqrt.v2f64 simd_fsqrt(a) } // CHECK-LABEL: @fsqrt_64x8 #[no_mangle] pub unsafe fn fsqrt_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.sqrt.v8f64 + // CHECK: call fast <8 x double> @llvm.sqrt.v8f64 simd_fsqrt(a) } diff --git a/src/test/codegen/simd-intrinsic-float-log.rs b/src/test/codegen/simd-intrinsic-float-log.rs index dd77294c824..d3829efe09b 100644 --- a/src/test/codegen/simd-intrinsic-float-log.rs +++ b/src/test/codegen/simd-intrinsic-float-log.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @log_32x2 #[no_mangle] pub unsafe fn log_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log.v2f32 + // CHECK: call fast <2 x float> @llvm.log.v2f32 simd_flog(a) } // CHECK-LABEL: @log_32x4 #[no_mangle] pub unsafe fn log_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log.v4f32 + // CHECK: call fast <4 x float> @llvm.log.v4f32 simd_flog(a) } // CHECK-LABEL: @log_32x8 #[no_mangle] pub unsafe fn log_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log.v8f32 + // CHECK: call fast <8 x float> @llvm.log.v8f32 simd_flog(a) } // CHECK-LABEL: @log_32x16 #[no_mangle] pub unsafe fn log_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log.v16f32 + // CHECK: call fast <16 x float> @llvm.log.v16f32 simd_flog(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @log_64x4 #[no_mangle] pub unsafe fn log_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log.v4f64 + // CHECK: call fast <4 x double> @llvm.log.v4f64 simd_flog(a) } // CHECK-LABEL: @log_64x2 #[no_mangle] pub unsafe fn log_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log.v2f64 + // CHECK: call fast <2 x double> @llvm.log.v2f64 simd_flog(a) } // CHECK-LABEL: @log_64x8 #[no_mangle] pub unsafe fn log_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log.v8f64 + // CHECK: call fast <8 x double> @llvm.log.v8f64 simd_flog(a) } diff --git a/src/test/codegen/simd-intrinsic-float-log10.rs b/src/test/codegen/simd-intrinsic-float-log10.rs index 0e094ac5b6e..47f19e499fa 100644 --- a/src/test/codegen/simd-intrinsic-float-log10.rs +++ b/src/test/codegen/simd-intrinsic-float-log10.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @log10_32x2 #[no_mangle] pub unsafe fn log10_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log10.v2f32 + // CHECK: call fast <2 x float> @llvm.log10.v2f32 simd_flog10(a) } // CHECK-LABEL: @log10_32x4 #[no_mangle] pub unsafe fn log10_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log10.v4f32 + // CHECK: call fast <4 x float> @llvm.log10.v4f32 simd_flog10(a) } // CHECK-LABEL: @log10_32x8 #[no_mangle] pub unsafe fn log10_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log10.v8f32 + // CHECK: call fast <8 x float> @llvm.log10.v8f32 simd_flog10(a) } // CHECK-LABEL: @log10_32x16 #[no_mangle] pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log10.v16f32 + // CHECK: call fast <16 x float> @llvm.log10.v16f32 simd_flog10(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @log10_64x4 #[no_mangle] pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log10.v4f64 + // CHECK: call fast <4 x double> @llvm.log10.v4f64 simd_flog10(a) } // CHECK-LABEL: @log10_64x2 #[no_mangle] pub unsafe fn log10_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log10.v2f64 + // CHECK: call fast <2 x double> @llvm.log10.v2f64 simd_flog10(a) } // CHECK-LABEL: @log10_64x8 #[no_mangle] pub unsafe fn log10_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log10.v8f64 + // CHECK: call fast <8 x double> @llvm.log10.v8f64 simd_flog10(a) } diff --git a/src/test/codegen/simd-intrinsic-float-log2.rs b/src/test/codegen/simd-intrinsic-float-log2.rs index da1207fc7ee..e36a5887b61 100644 --- a/src/test/codegen/simd-intrinsic-float-log2.rs +++ b/src/test/codegen/simd-intrinsic-float-log2.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @log2_32x2 #[no_mangle] pub unsafe fn log2_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log2.v2f32 + // CHECK: call fast <2 x float> @llvm.log2.v2f32 simd_flog2(a) } // CHECK-LABEL: @log2_32x4 #[no_mangle] pub unsafe fn log2_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log2.v4f32 + // CHECK: call fast <4 x float> @llvm.log2.v4f32 simd_flog2(a) } // CHECK-LABEL: @log2_32x8 #[no_mangle] pub unsafe fn log2_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log2.v8f32 + // CHECK: call fast <8 x float> @llvm.log2.v8f32 simd_flog2(a) } // CHECK-LABEL: @log2_32x16 #[no_mangle] pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log2.v16f32 + // CHECK: call fast <16 x float> @llvm.log2.v16f32 simd_flog2(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @log2_64x4 #[no_mangle] pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log2.v4f64 + // CHECK: call fast <4 x double> @llvm.log2.v4f64 simd_flog2(a) } // CHECK-LABEL: @log2_64x2 #[no_mangle] pub unsafe fn log2_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log2.v2f64 + // CHECK: call fast <2 x double> @llvm.log2.v2f64 simd_flog2(a) } // CHECK-LABEL: @log2_64x8 #[no_mangle] pub unsafe fn log2_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log2.v8f64 + // CHECK: call fast <8 x double> @llvm.log2.v8f64 simd_flog2(a) } diff --git a/src/test/codegen/simd-intrinsic-float-pow.rs b/src/test/codegen/simd-intrinsic-float-pow.rs index 5817dd49f4d..bb2ac362203 100644 --- a/src/test/codegen/simd-intrinsic-float-pow.rs +++ b/src/test/codegen/simd-intrinsic-float-pow.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fpow_32x2 #[no_mangle] pub unsafe fn fpow_32x2(a: f32x2, b: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.pow.v2f32 + // CHECK: call fast <2 x float> @llvm.pow.v2f32 simd_fpow(a, b) } // CHECK-LABEL: @fpow_32x4 #[no_mangle] pub unsafe fn fpow_32x4(a: f32x4, b: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.pow.v4f32 + // CHECK: call fast <4 x float> @llvm.pow.v4f32 simd_fpow(a, b) } // CHECK-LABEL: @fpow_32x8 #[no_mangle] pub unsafe fn fpow_32x8(a: f32x8, b: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.pow.v8f32 + // CHECK: call fast <8 x float> @llvm.pow.v8f32 simd_fpow(a, b) } // CHECK-LABEL: @fpow_32x16 #[no_mangle] pub unsafe fn fpow_32x16(a: f32x16, b: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.pow.v16f32 + // CHECK: call fast <16 x float> @llvm.pow.v16f32 simd_fpow(a, b) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fpow_64x4 #[no_mangle] pub unsafe fn fpow_64x4(a: f64x4, b: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.pow.v4f64 + // CHECK: call fast <4 x double> @llvm.pow.v4f64 simd_fpow(a, b) } // CHECK-LABEL: @fpow_64x2 #[no_mangle] pub unsafe fn fpow_64x2(a: f64x2, b: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.pow.v2f64 + // CHECK: call fast <2 x double> @llvm.pow.v2f64 simd_fpow(a, b) } // CHECK-LABEL: @fpow_64x8 #[no_mangle] pub unsafe fn fpow_64x8(a: f64x8, b: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.pow.v8f64 + // CHECK: call fast <8 x double> @llvm.pow.v8f64 simd_fpow(a, b) } diff --git a/src/test/codegen/simd-intrinsic-float-powi.rs b/src/test/codegen/simd-intrinsic-float-powi.rs index 2db5689f623..6e28af262ac 100644 --- a/src/test/codegen/simd-intrinsic-float-powi.rs +++ b/src/test/codegen/simd-intrinsic-float-powi.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fpowi_32x2 #[no_mangle] pub unsafe fn fpowi_32x2(a: f32x2, b: i32) -> f32x2 { - // CHECK: call <2 x float> @llvm.powi.v2f32 + // CHECK: call fast <2 x float> @llvm.powi.v2f32 simd_fpowi(a, b) } // CHECK-LABEL: @fpowi_32x4 #[no_mangle] pub unsafe fn fpowi_32x4(a: f32x4, b: i32) -> f32x4 { - // CHECK: call <4 x float> @llvm.powi.v4f32 + // CHECK: call fast <4 x float> @llvm.powi.v4f32 simd_fpowi(a, b) } // CHECK-LABEL: @fpowi_32x8 #[no_mangle] pub unsafe fn fpowi_32x8(a: f32x8, b: i32) -> f32x8 { - // CHECK: call <8 x float> @llvm.powi.v8f32 + // CHECK: call fast <8 x float> @llvm.powi.v8f32 simd_fpowi(a, b) } // CHECK-LABEL: @fpowi_32x16 #[no_mangle] pub unsafe fn fpowi_32x16(a: f32x16, b: i32) -> f32x16 { - // CHECK: call <16 x float> @llvm.powi.v16f32 + // CHECK: call fast <16 x float> @llvm.powi.v16f32 simd_fpowi(a, b) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fpowi_64x4 #[no_mangle] pub unsafe fn fpowi_64x4(a: f64x4, b: i32) -> f64x4 { - // CHECK: call <4 x double> @llvm.powi.v4f64 + // CHECK: call fast <4 x double> @llvm.powi.v4f64 simd_fpowi(a, b) } // CHECK-LABEL: @fpowi_64x2 #[no_mangle] pub unsafe fn fpowi_64x2(a: f64x2, b: i32) -> f64x2 { - // CHECK: call <2 x double> @llvm.powi.v2f64 + // CHECK: call fast <2 x double> @llvm.powi.v2f64 simd_fpowi(a, b) } // CHECK-LABEL: @fpowi_64x8 #[no_mangle] pub unsafe fn fpowi_64x8(a: f64x8, b: i32) -> f64x8 { - // CHECK: call <8 x double> @llvm.powi.v8f64 + // CHECK: call fast <8 x double> @llvm.powi.v8f64 simd_fpowi(a, b) } diff --git a/src/test/codegen/simd-intrinsic-float-sin.rs b/src/test/codegen/simd-intrinsic-float-sin.rs index 15720462db7..26100ed5c3f 100644 --- a/src/test/codegen/simd-intrinsic-float-sin.rs +++ b/src/test/codegen/simd-intrinsic-float-sin.rs @@ -44,28 +44,28 @@ extern "platform-intrinsic" { // CHECK-LABEL: @fsin_32x2 #[no_mangle] pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.sin.v2f32 + // CHECK: call fast <2 x float> @llvm.sin.v2f32 simd_fsin(a) } // CHECK-LABEL: @fsin_32x4 #[no_mangle] pub unsafe fn fsin_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.sin.v4f32 + // CHECK: call fast <4 x float> @llvm.sin.v4f32 simd_fsin(a) } // CHECK-LABEL: @fsin_32x8 #[no_mangle] pub unsafe fn fsin_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.sin.v8f32 + // CHECK: call fast <8 x float> @llvm.sin.v8f32 simd_fsin(a) } // CHECK-LABEL: @fsin_32x16 #[no_mangle] pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.sin.v16f32 + // CHECK: call fast <16 x float> @llvm.sin.v16f32 simd_fsin(a) } @@ -85,20 +85,20 @@ pub struct f64x8(pub f64, pub f64, pub f64, pub f64, // CHECK-LABEL: @fsin_64x4 #[no_mangle] pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.sin.v4f64 + // CHECK: call fast <4 x double> @llvm.sin.v4f64 simd_fsin(a) } // CHECK-LABEL: @fsin_64x2 #[no_mangle] pub unsafe fn fsin_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.sin.v2f64 + // CHECK: call fast <2 x double> @llvm.sin.v2f64 simd_fsin(a) } // CHECK-LABEL: @fsin_64x8 #[no_mangle] pub unsafe fn fsin_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.sin.v8f64 + // CHECK: call fast <8 x double> @llvm.sin.v8f64 simd_fsin(a) } -- cgit 1.4.1-3-g733a5 From f67453729c19b435686c94936d8145051e7f1284 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 24 May 2018 12:03:05 -0700 Subject: std: Ensure OOM is classified as `nounwind` OOM can't unwind today, and historically it's been optimized as if it can't unwind. This accidentally regressed with recent changes to the OOM handler, so this commit adds in a codegen test to assert that everything gets optimized away after the OOM function is approrpiately classified as nounwind Closes #50925 --- src/liballoc/alloc.rs | 1 + src/librustc_codegen_llvm/attributes.rs | 29 ++++++++++++++++++++++++----- src/librustc_codegen_llvm/callee.rs | 11 ----------- src/test/codegen/vec-iter-collect-len.rs | 21 +++++++++++++++++++++ 4 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 src/test/codegen/vec-iter-collect-len.rs (limited to 'src/test/codegen') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 79607b06f94..4ae8fc649dd 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -133,6 +133,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } } +#[rustc_allocator_nounwind] pub fn oom() -> ! { extern { #[lang = "oom"] diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index b64e102ba78..d6806e7afd3 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -20,7 +20,9 @@ use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::FxHashMap; +use rustc_target::spec::PanicStrategy; +use attributes; use llvm::{self, Attribute, ValueRef}; use llvm::AttributePlace::Function; use llvm_util; @@ -135,11 +137,28 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { Attribute::NoAlias.apply_llfn( llvm::AttributePlace::ReturnValue, llfn); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { - unwind(llfn, true); - } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { - unwind(llfn, false); + + let can_unwind = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { + Some(true) + } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { + Some(false) + + // Perhaps questionable, but we assume that anything defined + // *in Rust code* may unwind. Foreign items like `extern "C" { + // fn foo(); }` are assumed not to unwind **unless** they have + // a `#[unwind]` attribute. + } else if !cx.tcx.is_foreign_item(id) { + Some(true) + } else { + None + }; + + match can_unwind { + Some(false) => attributes::unwind(llfn, false), + Some(true) if cx.tcx.sess.panic_strategy() == PanicStrategy::Unwind => { + attributes::unwind(llfn, true); + } + Some(true) | None => {} } let features = llvm_target_features(cx.tcx.sess) diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index a3dbc450ce7..2c01bd42cc7 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -26,7 +26,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::Substs; -use rustc_target::spec::PanicStrategy; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -102,16 +101,6 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let instance_def_id = instance.def_id(); - // Perhaps questionable, but we assume that anything defined - // *in Rust code* may unwind. Foreign items like `extern "C" { - // fn foo(); }` are assumed not to unwind **unless** they have - // a `#[unwind]` attribute. - if tcx.sess.panic_strategy() == PanicStrategy::Unwind { - if !tcx.is_foreign_item(instance_def_id) { - attributes::unwind(llfn, true); - } - } - // Apply an appropriate linkage/visibility value to our item that we // just declared. // diff --git a/src/test/codegen/vec-iter-collect-len.rs b/src/test/codegen/vec-iter-collect-len.rs new file mode 100644 index 00000000000..efb384d0afb --- /dev/null +++ b/src/test/codegen/vec-iter-collect-len.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-system-llvm +// compile-flags: -O +#![crate_type="lib"] + +#[no_mangle] +pub fn get_len() -> usize { + // CHECK-LABEL: @get_len + // CHECK-NOT: call + // CHECK-NOT: invoke + [1, 2, 3].iter().collect::>().len() +} -- cgit 1.4.1-3-g733a5 From 690240994f0c1cd299e35f7b1db2538515ba5910 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Mon, 4 Jun 2018 13:27:32 +0200 Subject: test: Ignore some problematic tests on sparc and sparc64 --- src/test/codegen/abi-main-signature-16bit-c-int.rs | 1 + src/test/codegen/fastcall-inreg.rs | 1 + src/test/codegen/repr-transparent-aggregates-2.rs | 2 ++ src/test/codegen/stack-probes.rs | 2 ++ src/test/codegen/x86_mmx.rs | 2 ++ src/test/compile-fail/asm-bad-clobber.rs | 1 + src/test/compile-fail/asm-in-bad-modifier.rs | 1 + src/test/compile-fail/asm-misplaced-option.rs | 1 + src/test/compile-fail/asm-out-no-modifier.rs | 1 + src/test/compile-fail/asm-out-read-uninit.rs | 1 + src/test/compile-fail/borrowck/borrowck-asm.rs | 1 + src/test/run-pass/stack-probes-lto.rs | 2 ++ src/test/run-pass/stack-probes.rs | 2 ++ src/test/ui/asm-out-assign-imm.rs | 1 + src/test/ui/asm-out-assign-imm.stderr | 2 +- src/test/ui/target-feature-wrong.rs | 2 ++ src/test/ui/target-feature-wrong.stderr | 14 +++++++------- 17 files changed, 29 insertions(+), 8 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index 367d509cadf..df5cba1c244 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -22,6 +22,7 @@ // ignore-powerpc64 // ignore-s390x // ignore-sparc +// ignore-sparc64 // ignore-wasm32 // ignore-x86 // ignore-x86_64 diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index d6dd3f356b5..77e3781961f 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -29,6 +29,7 @@ // ignore-r600 // ignore-amdgcn // ignore-sparc +// ignore-sparc64 // ignore-sparcv9 // ignore-sparcel // ignore-s390x diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 9605ded569e..25750a6513f 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -14,6 +14,8 @@ // ignore-asmjs // ignore-mips64 // ignore-s390x +// ignore-sparc +// ignore-sparc64 // ignore-wasm // ignore-x86 // ignore-x86_64 diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 51ebc42a0dd..2c86e609e7b 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -14,6 +14,8 @@ // ignore-mips64 // ignore-powerpc // ignore-s390x +// ignore-sparc +// ignore-sparc64 // ignore-wasm // ignore-emscripten // ignore-windows diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index 30777c6214e..ba51004a791 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -13,6 +13,8 @@ // ignore-emscripten // ignore-mips // ignore-mips64 +// ignore-sparc +// ignore-sparc64 // compile-flags: -O #![feature(repr_simd)] diff --git a/src/test/compile-fail/asm-bad-clobber.rs b/src/test/compile-fail/asm-bad-clobber.rs index aa77e7f46e5..900f5cce13b 100644 --- a/src/test/compile-fail/asm-bad-clobber.rs +++ b/src/test/compile-fail/asm-bad-clobber.rs @@ -15,6 +15,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips // ignore-mips64 diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs index 5e9278c7c35..3960fd50e17 100644 --- a/src/test/compile-fail/asm-in-bad-modifier.rs +++ b/src/test/compile-fail/asm-in-bad-modifier.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips // ignore-mips64 diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs index abd55ea1011..77798201ff3 100644 --- a/src/test/compile-fail/asm-misplaced-option.rs +++ b/src/test/compile-fail/asm-misplaced-option.rs @@ -15,6 +15,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips // ignore-mips64 diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs index 55d8970008f..e38112a2566 100644 --- a/src/test/compile-fail/asm-out-no-modifier.rs +++ b/src/test/compile-fail/asm-out-no-modifier.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips // ignore-mips64 diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs index c606c5a80e5..bd0301e6cf9 100644 --- a/src/test/compile-fail/asm-out-read-uninit.rs +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips // ignore-mips64 diff --git a/src/test/compile-fail/borrowck/borrowck-asm.rs b/src/test/compile-fail/borrowck/borrowck-asm.rs index 0b230be85ad..4cd74117ef7 100644 --- a/src/test/compile-fail/borrowck/borrowck-asm.rs +++ b/src/test/compile-fail/borrowck/borrowck-asm.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // revisions: ast mir //[mir]compile-flags: -Z borrowck=mir diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index d1cb75909c1..3fef19c51bd 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -14,6 +14,8 @@ // ignore-mips64 // ignore-powerpc // ignore-s390x +// ignore-sparc +// ignore-sparc64 // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index 78c5782be38..c93dcf01939 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -14,6 +14,8 @@ // ignore-mips64 // ignore-powerpc // ignore-s390x +// ignore-sparc +// ignore-sparc64 // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes diff --git a/src/test/ui/asm-out-assign-imm.rs b/src/test/ui/asm-out-assign-imm.rs index 055a169deda..73a709b1686 100644 --- a/src/test/ui/asm-out-assign-imm.rs +++ b/src/test/ui/asm-out-assign-imm.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-sparc64 // ignore-mips #![feature(asm)] diff --git a/src/test/ui/asm-out-assign-imm.stderr b/src/test/ui/asm-out-assign-imm.stderr index d9fd4b26c39..324dec77adc 100644 --- a/src/test/ui/asm-out-assign-imm.stderr +++ b/src/test/ui/asm-out-assign-imm.stderr @@ -1,5 +1,5 @@ error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/asm-out-assign-imm.rs:30:9 + --> $DIR/asm-out-assign-imm.rs:31:9 | LL | x = 1; | ----- first assignment to `x` diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index 0edd51ba779..ed9bbb60dcd 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -15,6 +15,8 @@ // ignore-mips // ignore-powerpc // ignore-s390x +// ignore-sparc +// ignore-sparc64 #![feature(target_feature)] diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr index ed86687bb2f..39362f74bdd 100644 --- a/src/test/ui/target-feature-wrong.stderr +++ b/src/test/ui/target-feature-wrong.stderr @@ -1,35 +1,35 @@ error: #[target_feature] attribute must be of the form #[target_feature(..)] - --> $DIR/target-feature-wrong.rs:21:1 + --> $DIR/target-feature-wrong.rs:23:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the feature named `foo` is not valid for this target - --> $DIR/target-feature-wrong.rs:23:18 + --> $DIR/target-feature-wrong.rs:25:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:25:18 + --> $DIR/target-feature-wrong.rs:27:18 | LL | #[target_feature(bar)] | ^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:27:18 + --> $DIR/target-feature-wrong.rs:29:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ error: #[target_feature(..)] can only be applied to `unsafe` function - --> $DIR/target-feature-wrong.rs:31:1 + --> $DIR/target-feature-wrong.rs:33:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a function - --> $DIR/target-feature-wrong.rs:35:1 + --> $DIR/target-feature-wrong.rs:37:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | mod another {} | -------------- not a function error: cannot use #[inline(always)] with #[target_feature] - --> $DIR/target-feature-wrong.rs:39:1 + --> $DIR/target-feature-wrong.rs:41:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From e2aef92c19a95d6a0b8e75b473023f77de6150f0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 13:24:16 +0200 Subject: Stabilize #[repr(transparent)] Tracking issue FCP: https://github.com/rust-lang/rust/issues/43036#issuecomment-394094318 Reference PR: https://github.com/rust-lang-nursery/reference/pull/353 --- .../src/language-features/repr-transparent.md | 176 --------------------- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/librustc/diagnostics.rs | 8 - src/librustc_typeck/diagnostics.rs | 10 +- src/libsyntax/feature_gate.rs | 10 +- src/test/codegen/repr-transparent-aggregates-1.rs | 1 - src/test/codegen/repr-transparent-aggregates-2.rs | 1 - src/test/codegen/repr-transparent-aggregates-3.rs | 1 - src/test/codegen/repr-transparent-sysv64.rs | 1 - src/test/codegen/repr-transparent.rs | 2 +- .../compile-fail/repr-transparent-other-items.rs | 2 - .../compile-fail/repr-transparent-other-reprs.rs | 2 +- src/test/compile-fail/repr-transparent.rs | 1 - src/test/ui/feature-gate-repr_transparent.rs | 14 -- src/test/ui/feature-gate-repr_transparent.stderr | 11 -- src/test/ui/lint-ctypes.rs | 2 +- 17 files changed, 9 insertions(+), 237 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/repr-transparent.md delete mode 100644 src/test/ui/feature-gate-repr_transparent.rs delete mode 100644 src/test/ui/feature-gate-repr_transparent.stderr (limited to 'src/test/codegen') diff --git a/src/doc/unstable-book/src/language-features/repr-transparent.md b/src/doc/unstable-book/src/language-features/repr-transparent.md deleted file mode 100644 index 62202dc96fd..00000000000 --- a/src/doc/unstable-book/src/language-features/repr-transparent.md +++ /dev/null @@ -1,176 +0,0 @@ -# `repr_transparent` - -The tracking issue for this feature is: [#43036] - -[#43036]: https://github.com/rust-lang/rust/issues/43036 - ------------------------- - -This feature enables the `repr(transparent)` attribute on structs, which enables -the use of newtypes without the usual ABI implications of wrapping the value in -a struct. - -## Background - -It's sometimes useful to add additional type safety by introducing *newtypes*. -For example, code that handles numeric quantities in different units such as -millimeters, centimeters, grams, kilograms, etc. may want to use the type system -to rule out mistakes such as adding millimeters to grams: - -```rust -use std::ops::Add; - -struct Millimeters(f64); -struct Grams(f64); - -impl Add for Millimeters { - type Output = Millimeters; - - fn add(self, other: Millimeters) -> Millimeters { - Millimeters(self.0 + other.0) - } -} - -// Likewise: impl Add for Grams {} -``` - -Other uses of newtypes include using `PhantomData` to add lifetimes to raw -pointers or to implement the "phantom types" pattern. See the [PhantomData] -documentation and [the Nomicon][nomicon-phantom] for more details. - -The added type safety is especially useful when interacting with C or other -languages. However, in those cases we need to ensure the newtypes we add do not -introduce incompatibilities with the C ABI. - -## Newtypes in FFI - -Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all -platforms which Rust currently supports, and likely on many more. For example, -consider this C declaration: - -```C -struct Object { - double weight; //< in grams - double height; //< in millimeters - // ... -} - -void frobnicate(struct Object *); -``` - -While using this C code from Rust, we could add `repr(C)` to the `Grams` and -`Millimeters` newtypes introduced above and use them to add some type safety -while staying compatible with the memory layout of `Object`: - -```rust,no_run -#[repr(C)] -struct Grams(f64); - -#[repr(C)] -struct Millimeters(f64); - -#[repr(C)] -struct Object { - weight: Grams, - height: Millimeters, - // ... -} - -extern { - fn frobnicate(_: *mut Object); -} -``` - -This works even when adding some `PhantomData` fields, because they are -zero-sized and therefore don't have to affect the memory layout. - -However, there's more to the ABI than just memory layout: there's also the -question of how function call arguments and return values are passed. Many -common ABI treat a struct containing a single field differently from that field -itself, at least when the field is a scalar (e.g., integer or float or pointer). - -To continue the above example, suppose the C library also exposes a function -like this: - -```C -double calculate_weight(double height); -``` - -Using our newtypes on the Rust side like this will cause an ABI mismatch on many -platforms: - -```rust,ignore -extern { - fn calculate_weight(height: Millimeters) -> Grams; -} -``` - -For example, on x86_64 Linux, Rust will pass the argument in an integer -register, while the C function expects the argument to be in a floating-point -register. Likewise, the C function will return the result in a floating-point -register while Rust will expect it in an integer register. - -Note that this problem is not specific to floats: To give another example, -32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while -`i32` is placed in registers. - -## Enter `repr(transparent)` - -So while `repr(C)` happens to do the right thing with respect to memory layout, -it's not quite the right tool for newtypes in FFI. Instead of declaring a C -struct, we need to communicate to the Rust compiler that our newtype is just for -type safety on the Rust side. This is what `repr(transparent)` does. - -The attribute can be applied to a newtype-like structs that contains a single -field. It indicates that the newtype should be represented exactly like that -field's type, i.e., the newtype should be ignored for ABI purpopses: not only is -it laid out the same in memory, it is also passed identically in function calls. - -In the above example, the ABI mismatches can be prevented by making the newtypes -`Grams` and `Millimeters` transparent like this: - -```rust -#![feature(repr_transparent)] - -#[repr(transparent)] -struct Grams(f64); - -#[repr(transparent)] -struct Millimeters(f64); -``` - -In addition to that single field, any number of zero-sized fields are permitted, -including but not limited to `PhantomData`: - -```rust -#![feature(repr_transparent)] - -use std::marker::PhantomData; - -struct Foo { /* ... */ } - -#[repr(transparent)] -struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>); - -#[repr(transparent)] -struct NumberWithUnit(T, PhantomData); - -struct CustomZst; - -#[repr(transparent)] -struct PtrWithCustomZst<'a> { - ptr: FooPtrWithLifetime<'a>, - some_marker: CustomZst, -} -``` - -Transparent structs can be nested: `PtrWithCustomZst` is also represented -exactly like `*const Foo`. - -Because `repr(transparent)` delegates all representation concerns to another -type, it is incompatible with all other `repr(..)` attributes. It also cannot be -applied to enums, unions, empty structs, structs whose fields are all -zero-sized, or structs with *multiple* non-zero-sized fields. - -[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html -[nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 74bbd659246..e25742a4a61 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -105,7 +105,7 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(staged_api)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ba77edee6e..40caee85541 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,7 +100,7 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 7415ddd455d..1435957a5c1 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1958,8 +1958,6 @@ representation hints. Erroneous code example: ```compile_fail,E0692 -#![feature(repr_transparent)] - #[repr(transparent, C)] // error: incompatible representation hints struct Grams(f32); ``` @@ -1969,8 +1967,6 @@ another type, so adding more representation hints is contradictory. Remove either the `transparent` hint or the other hints, like this: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); ``` @@ -1978,8 +1974,6 @@ struct Grams(f32); Alternatively, move the other attributes to the contained type: ``` -#![feature(repr_transparent)] - #[repr(C)] struct Foo { x: i32, @@ -1994,8 +1988,6 @@ Note that introducing another `struct` just to have a place for the other attributes may have unintended side effects on the representation: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e4c73218de5..da54eeabdb9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4581,8 +4581,6 @@ on fields that were not guaranteed to be zero-sized. Erroneous code example: ```compile_fail,E0690 -#![feature(repr_transparent)] - #[repr(transparent)] struct LengthWithUnit { // error: transparent struct needs exactly one value: f32, // non-zero-sized field, but has 2 @@ -4602,8 +4600,6 @@ To combine `repr(transparent)` with type parameters, `PhantomData` may be useful: ``` -#![feature(repr_transparent)] - use std::marker::PhantomData; #[repr(transparent)] @@ -4621,7 +4617,7 @@ field that requires non-trivial alignment. Erroneous code example: ```compile_fail,E0691 -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] #[repr(align(32))] struct ForceAlign32; @@ -4640,8 +4636,6 @@ requirement. Consider removing the over-aligned zero-sized field: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Wrapper(f32); ``` @@ -4650,7 +4644,7 @@ Alternatively, `PhantomData` has alignment 1 for all `T`, so you can use it if you need to keep the field for some reason: ``` -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] use std::marker::PhantomData; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1535e649506..9f370672cb2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -399,9 +399,6 @@ declare_features! ( // `extern` in paths (active, extern_in_paths, "1.23.0", Some(44660), None), - // Allows `#[repr(transparent)]` attribute on newtype structs - (active, repr_transparent, "1.25.0", Some(43036), None), - // Use `?` as the Kleene "at most one" operator (active, macro_at_most_once_rep, "1.25.0", Some(48075), None), @@ -615,6 +612,8 @@ declare_features! ( (accepted, termination_trait_test, "1.27.0", Some(48854), None), // The #[global_allocator] attribute (accepted, global_allocator, "1.28.0", Some(27389), None), + // Allows `#[repr(transparent)]` attribute on newtype structs + (accepted, repr_transparent, "1.28.0", Some(43036), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1595,11 +1594,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } - if item.check_name("transparent") { - gate_feature_post!(&self, repr_transparent, attr.span, - "the `#[repr(transparent)]` attribute \ - is experimental"); - } if let Some((name, _)) = item.name_value_literal() { if name == "packed" { gate_feature_post!(&self, repr_packed, attr.span, diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788c..a1185cc1e2e 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -18,7 +18,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 25750a6513f..bc000bd3165 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -22,7 +22,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs index 0c90239c9de..a292f1d70f3 100644 --- a/src/test/codegen/repr-transparent-aggregates-3.rs +++ b/src/test/codegen/repr-transparent-aggregates-3.rs @@ -14,7 +14,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-sysv64.rs b/src/test/codegen/repr-transparent-sysv64.rs index 7a30983fdd3..2e4665e22e3 100644 --- a/src/test/codegen/repr-transparent-sysv64.rs +++ b/src/test/codegen/repr-transparent-sysv64.rs @@ -13,7 +13,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] pub struct Rgb8 { r: u8, g: u8, b: u8 } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index 087fa9b16b4..64a62fd7e88 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -11,7 +11,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent, repr_simd)] +#![feature(repr_simd)] use std::marker::PhantomData; diff --git a/src/test/compile-fail/repr-transparent-other-items.rs b/src/test/compile-fail/repr-transparent-other-items.rs index cf0870866c7..685d62dc3a9 100644 --- a/src/test/compile-fail/repr-transparent-other-items.rs +++ b/src/test/compile-fail/repr-transparent-other-items.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent)] - // See also repr-transparent.rs #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum diff --git a/src/test/compile-fail/repr-transparent-other-reprs.rs b/src/test/compile-fail/repr-transparent-other-reprs.rs index 7b91a6f68e3..a391c0ae1f8 100644 --- a/src/test/compile-fail/repr-transparent-other-reprs.rs +++ b/src/test/compile-fail/repr-transparent-other-reprs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] // See also repr-transparent.rs diff --git a/src/test/compile-fail/repr-transparent.rs b/src/test/compile-fail/repr-transparent.rs index b5e6a0fa0b1..4d8ec4cdb40 100644 --- a/src/test/compile-fail/repr-transparent.rs +++ b/src/test/compile-fail/repr-transparent.rs @@ -14,7 +14,6 @@ // - repr-transparent-other-items.rs #![feature(repr_align, attr_literals)] -#![feature(repr_transparent)] use std::marker::PhantomData; diff --git a/src/test/ui/feature-gate-repr_transparent.rs b/src/test/ui/feature-gate-repr_transparent.rs deleted file mode 100644 index deadf2e535d..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental -struct Foo(u64); - -fn main() {} diff --git a/src/test/ui/feature-gate-repr_transparent.stderr b/src/test/ui/feature-gate-repr_transparent.stderr deleted file mode 100644 index a4ffaa26690..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036) - --> $DIR/feature-gate-repr_transparent.rs:11:1 - | -LL | #[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_transparent)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 85957831653..4b20001457f 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, repr_transparent)] +#![feature(libc)] extern crate libc; -- cgit 1.4.1-3-g733a5 From d63aabcb3662f82168a0d1f9795ff0b828c24c24 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Wed, 6 Jun 2018 00:12:00 +0200 Subject: test: Ignore some problematic tests on powerpc and powerpc64* --- src/test/codegen/repr-transparent-aggregates-2.rs | 3 +++ src/test/codegen/stack-probes.rs | 2 ++ src/test/codegen/x86_mmx.rs | 3 +++ src/test/compile-fail/asm-bad-clobber.rs | 2 ++ src/test/compile-fail/asm-in-bad-modifier.rs | 2 ++ src/test/compile-fail/asm-misplaced-option.rs | 2 ++ src/test/compile-fail/asm-out-no-modifier.rs | 2 ++ src/test/compile-fail/asm-out-read-uninit.rs | 2 ++ src/test/compile-fail/borrowck/borrowck-asm.rs | 2 ++ src/test/ui/asm-out-assign-imm.rs | 2 ++ src/test/ui/asm-out-assign-imm.stderr | 2 +- src/test/ui/target-feature-wrong.rs | 2 ++ src/test/ui/target-feature-wrong.stderr | 14 +++++++------- 13 files changed, 32 insertions(+), 8 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index bc000bd3165..b4623eb4913 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -13,6 +13,9 @@ // ignore-aarch64 // ignore-asmjs // ignore-mips64 +// ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 2c86e609e7b..6ab71723a1d 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -13,6 +13,8 @@ // ignore-mips // ignore-mips64 // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index ba51004a791..4424c30e0f8 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -13,6 +13,9 @@ // ignore-emscripten // ignore-mips // ignore-mips64 +// ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // compile-flags: -O diff --git a/src/test/compile-fail/asm-bad-clobber.rs b/src/test/compile-fail/asm-bad-clobber.rs index 900f5cce13b..c2b54e37e39 100644 --- a/src/test/compile-fail/asm-bad-clobber.rs +++ b/src/test/compile-fail/asm-bad-clobber.rs @@ -14,6 +14,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs index 3960fd50e17..2eefd4235bc 100644 --- a/src/test/compile-fail/asm-in-bad-modifier.rs +++ b/src/test/compile-fail/asm-in-bad-modifier.rs @@ -11,6 +11,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs index 77798201ff3..bfc1fd68fe0 100644 --- a/src/test/compile-fail/asm-misplaced-option.rs +++ b/src/test/compile-fail/asm-misplaced-option.rs @@ -14,6 +14,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs index e38112a2566..40d2ded8a88 100644 --- a/src/test/compile-fail/asm-out-no-modifier.rs +++ b/src/test/compile-fail/asm-out-no-modifier.rs @@ -11,6 +11,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs index bd0301e6cf9..c308a9f0850 100644 --- a/src/test/compile-fail/asm-out-read-uninit.rs +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -11,6 +11,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/compile-fail/borrowck/borrowck-asm.rs b/src/test/compile-fail/borrowck/borrowck-asm.rs index 4cd74117ef7..d9816401b33 100644 --- a/src/test/compile-fail/borrowck/borrowck-asm.rs +++ b/src/test/compile-fail/borrowck/borrowck-asm.rs @@ -11,6 +11,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 diff --git a/src/test/ui/asm-out-assign-imm.rs b/src/test/ui/asm-out-assign-imm.rs index 73a709b1686..f5bb07a9b35 100644 --- a/src/test/ui/asm-out-assign-imm.rs +++ b/src/test/ui/asm-out-assign-imm.rs @@ -11,6 +11,8 @@ // ignore-s390x // ignore-emscripten // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-sparc // ignore-sparc64 // ignore-mips diff --git a/src/test/ui/asm-out-assign-imm.stderr b/src/test/ui/asm-out-assign-imm.stderr index 324dec77adc..7075914fa04 100644 --- a/src/test/ui/asm-out-assign-imm.stderr +++ b/src/test/ui/asm-out-assign-imm.stderr @@ -1,5 +1,5 @@ error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/asm-out-assign-imm.rs:31:9 + --> $DIR/asm-out-assign-imm.rs:33:9 | LL | x = 1; | ----- first assignment to `x` diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index ed9bbb60dcd..8983c0ea79b 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -14,6 +14,8 @@ // ignore-emscripten // ignore-mips // ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr index 39362f74bdd..d4e1c978104 100644 --- a/src/test/ui/target-feature-wrong.stderr +++ b/src/test/ui/target-feature-wrong.stderr @@ -1,35 +1,35 @@ error: #[target_feature] attribute must be of the form #[target_feature(..)] - --> $DIR/target-feature-wrong.rs:23:1 + --> $DIR/target-feature-wrong.rs:25:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the feature named `foo` is not valid for this target - --> $DIR/target-feature-wrong.rs:25:18 + --> $DIR/target-feature-wrong.rs:27:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:27:18 + --> $DIR/target-feature-wrong.rs:29:18 | LL | #[target_feature(bar)] | ^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:29:18 + --> $DIR/target-feature-wrong.rs:31:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ error: #[target_feature(..)] can only be applied to `unsafe` function - --> $DIR/target-feature-wrong.rs:33:1 + --> $DIR/target-feature-wrong.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a function - --> $DIR/target-feature-wrong.rs:37:1 + --> $DIR/target-feature-wrong.rs:39:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | mod another {} | -------------- not a function error: cannot use #[inline(always)] with #[target_feature] - --> $DIR/target-feature-wrong.rs:41:1 + --> $DIR/target-feature-wrong.rs:43:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From e3d113eca91d639c697d925d9de38b5efde70c1b Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 28 Jun 2018 06:24:09 +0800 Subject: Do not allow LLVM to increase a TLS's alignment on macOS. --- src/librustc_codegen_llvm/consts.rs | 40 ++++++++++++++++++++++++- src/librustc_codegen_llvm/mir/constant.rs | 4 +-- src/test/codegen/issue-44056-macos-tls-align.rs | 40 +++++++++++++++++++++++++ src/test/run-pass/issue-44056.rs | 15 ++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/issue-44056-macos-tls-align.rs create mode 100644 src/test/run-pass/issue-44056.rs (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index afa81465ea2..199c40bb704 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -250,7 +250,7 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unsafe { let g = get_static(cx, def_id); - let v = match ::mir::codegen_static_initializer(cx, def_id) { + let (v, alloc) = match ::mir::codegen_static_initializer(cx, def_id) { Ok(v) => v, // Error has already been reported Err(_) => return, @@ -309,6 +309,44 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, if attr::contains_name(attrs, "thread_local") { llvm::set_thread_local_mode(g, cx.tls_model); + + // Do not allow LLVM to change the alignment of a TLS on macOS. + // + // By default a global's alignment can be freely increased. + // This allows LLVM to generate more performant instructions + // e.g. using load-aligned into a SIMD register. + // + // However, on macOS 10.10 or below, the dynamic linker does not + // respect any alignment given on the TLS (radar 24221680). + // This will violate the alignment assumption, and causing segfault at runtime. + // + // This bug is very easy to trigger. In `println!` and `panic!`, + // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, + // which the values would be `mem::replace`d on initialization. + // The implementation of `mem::replace` will use SIMD + // whenever the size is 32 bytes or higher. LLVM notices SIMD is used + // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, + // which macOS's dyld disregarded and causing crashes + // (see issues #51794, #51758, #50867, #48866 and #44056). + // + // To workaround the bug, we trick LLVM into not increasing + // the global's alignment by explicitly assigning a section to it + // (equivalent to automatically generating a `#[link_section]` attribute). + // See the comment in the `GlobalValue::canIncreaseAlignment()` function + // of `lib/IR/Globals.cpp` for why this works. + // + // When the alignment is not increased, the optimized `mem::replace` + // will use load-unaligned instructions instead, and thus avoiding the crash. + // + // We could remove this hack whenever we decide to drop macOS 10.10 support. + if cx.tcx.sess.target.target.options.is_like_osx { + let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { + CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") + } else { + CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") + }; + llvm::LLVMSetSection(g, sect_name.as_ptr()); + } } base::set_link_section(cx, g, attrs); diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index bbe0e34b48f..d7939bd2ab2 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -118,7 +118,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { pub fn codegen_static_initializer<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, def_id: DefId) - -> Result>> + -> Result<(ValueRef, &'tcx Allocation), Lrc>> { let instance = ty::Instance::mono(cx.tcx, def_id); let cid = GlobalId { @@ -132,7 +132,7 @@ pub fn codegen_static_initializer<'a, 'tcx>( ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc, _ => bug!("static const eval returned {:#?}", static_), }; - Ok(const_alloc_to_llvm(cx, alloc)) + Ok((const_alloc_to_llvm(cx, alloc), alloc)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs new file mode 100644 index 00000000000..3235ef0bb33 --- /dev/null +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// only-macos +// no-system-llvm +// min-llvm-version 6.0 +// compile-flags: -O + +#![crate_type = "rlib"] +#![feature(thread_local)] + +// CHECK: @STATIC_VAR_1 = internal thread_local unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 +#[no_mangle] +#[allow(private_no_mangle_statics)] +#[thread_local] +static mut STATIC_VAR_1: [u32; 8] = [0; 8]; + +// CHECK: @STATIC_VAR_2 = internal thread_local unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 +#[no_mangle] +#[allow(private_no_mangle_statics)] +#[thread_local] +static mut STATIC_VAR_2: [u32; 8] = [4; 8]; + +#[no_mangle] +pub unsafe fn f(x: &mut [u32; 8]) { + std::mem::swap(x, &mut STATIC_VAR_1) +} + +#[no_mangle] +pub unsafe fn g(x: &mut [u32; 8]) { + std::mem::swap(x, &mut STATIC_VAR_2) +} diff --git a/src/test/run-pass/issue-44056.rs b/src/test/run-pass/issue-44056.rs new file mode 100644 index 00000000000..dcaa0bf8629 --- /dev/null +++ b/src/test/run-pass/issue-44056.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 +// no-prefer-dynamic +// compile-flags: -Ctarget-feature=+avx -Clto + +fn main() {} -- cgit 1.4.1-3-g733a5 From e5789765606baebd983bd9b1c870cb8b57a0627b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 15 Jun 2018 15:47:54 -0700 Subject: Store scalar pair bools as i8 in memory We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates, to optimize IR for checked operators and the like. With this patch, we still do so when the pair is an immediate value, but we use the `i8` memory type when the value is loaded or stored as an LLVM aggregate. So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }` in memory. When a pair is a direct function argument, `PassMode::Pair`, it is still passed using the immediate `i1` type, but as a return value it will use the `i8` memory type. Also, `bool`-like` enum tags will now use scalar pairs when possible, where they were previously excluded due to optimization issues. --- src/librustc/ty/layout.rs | 9 ++----- src/librustc_codegen_llvm/abi.rs | 4 ++-- src/librustc_codegen_llvm/base.rs | 15 ++++++++---- src/librustc_codegen_llvm/mir/operand.rs | 23 +++++++++--------- src/librustc_codegen_llvm/mir/place.rs | 6 ++--- src/librustc_codegen_llvm/mir/rvalue.rs | 4 ++-- src/librustc_codegen_llvm/type_of.rs | 25 ++++++++++---------- src/test/codegen/function-arguments.rs | 2 +- src/test/codegen/scalar-pair-bool.rs | 40 ++++++++++++++++++++++++++++++++ 9 files changed, 84 insertions(+), 44 deletions(-) create mode 100644 src/test/codegen/scalar-pair-bool.rs (limited to 'src/test/codegen') diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a32fdbb285d..faad32a5d99 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1020,13 +1020,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut abi = Abi::Aggregate { sized: true }; if tag.value.size(dl) == size { abi = Abi::Scalar(tag.clone()); - } else if !tag.is_bool() { - // HACK(nox): Blindly using ScalarPair for all tagged enums - // where applicable leads to Option being handled as {i1, i8}, - // which later confuses SROA and some loop optimisations, - // ultimately leading to the repeat-trusted-len test - // failing. We make the trade-off of using ScalarPair only - // for types where the tag isn't a boolean. + } else { + // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { let offsets = match layout_variant.fields { diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 6b5baa402b4..4ff31ec7d1c 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -582,8 +582,8 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0)); - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } PassMode::Cast(cast) => cast.llvm_type(cx), diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index a4709739a23..4605b5f3f1d 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -265,8 +265,8 @@ pub fn unsize_thin_ptr<'a, 'tcx>( } let (lldata, llextra) = result.unwrap(); // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)), - bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1))) + (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)), + bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true))) } _ => bug!("unsize_thin_ptr: called on bad types"), } @@ -396,9 +396,14 @@ pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef { pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { if let layout::Abi::Scalar(ref scalar) = layout.abi { - if scalar.is_bool() { - return bx.trunc(val, Type::i1(bx.cx)); - } + return to_immediate_scalar(bx, val, scalar); + } + val +} + +pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef { + if scalar.is_bool() { + return bx.trunc(val, Type::i1(bx.cx)); } val } diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index 3d3a4400bd8..3069a155d1f 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -128,13 +128,13 @@ impl<'a, 'tcx> OperandRef<'tcx> { bx.cx, a, a_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 0), + layout.scalar_pair_element_llvm_type(bx.cx, 0, true), ); let b_llval = scalar_to_llvm( bx.cx, b, b_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 1), + layout.scalar_pair_element_llvm_type(bx.cx, 1, true), ); OperandValue::Pair(a_llval, b_llval) }, @@ -193,8 +193,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { self, llty); // Reconstruct the immediate aggregate. let mut llpair = C_undef(llty); - llpair = bx.insert_value(llpair, a, 0); - llpair = bx.insert_value(llpair, b, 1); + llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0); + llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1); llpair } else { self.immediate() @@ -206,13 +206,14 @@ impl<'a, 'tcx> OperandRef<'tcx> { llval: ValueRef, layout: TyLayout<'tcx>) -> OperandRef<'tcx> { - let val = if layout.is_llvm_scalar_pair() { + let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. - OperandValue::Pair(bx.extract_value(llval, 0), - bx.extract_value(llval, 1)) + let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a); + let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b); + OperandValue::Pair(a_llval, b_llval) } else { OperandValue::Immediate(llval) }; @@ -264,8 +265,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx)); } OperandValue::Pair(ref mut a, ref mut b) => { - *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0)); - *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1)); + *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true)); + *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true)); } OperandValue::Ref(..) => bug!() } @@ -308,10 +309,10 @@ impl<'a, 'tcx> OperandValue { } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { - let mut llptr = bx.struct_gep(dest.llval, i as u64); + let llptr = bx.struct_gep(dest.llval, i as u64); // Make sure to always store i1 as i8. if common::val_ty(x) == Type::i1(bx.cx) { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + assert_eq!(common::val_ty(llptr), Type::i8p(bx.cx)); } let val = base::from_immediate(bx, x); bx.store_with_flags(val, llptr, dest.align, flags); diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 2a1e3980adb..36dcd04b02e 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; -use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big, val_ty}; use consts; use type_of::LayoutLlvmExt; use type_::Type; @@ -127,10 +127,10 @@ impl<'a, 'tcx> PlaceRef<'tcx> { OperandValue::Immediate(base::to_immediate(bx, llval, self.layout)) } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { let load = |i, scalar: &layout::Scalar| { - let mut llptr = bx.struct_gep(self.llval, i as u64); + let llptr = bx.struct_gep(self.llval, i as u64); // Make sure to always load i1 as i8. if scalar.is_bool() { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + assert_eq!(val_ty(llptr), Type::i8p(bx.cx)); } let load = bx.load(llptr, self.align); scalar_load_metadata(load, scalar); diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index 0fd81c6074e..2e81fc16a58 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // HACK(eddyb) have to bitcast pointers // until LLVM removes pointee types. let lldata = bx.pointercast(lldata, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(lldata, llextra) } OperandValue::Immediate(lldata) => { @@ -251,7 +251,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let OperandValue::Pair(data_ptr, meta) = operand.val { if cast.is_llvm_scalar_pair() { let data_cast = bx.pointercast(data_ptr, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(data_cast, meta) } else { // cast to thin-ptr // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 88b75ff9c09..195f1c3b85a 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -47,8 +47,8 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } layout::Abi::ScalarPair(..) => { return Type::struct_(cx, &[ - layout.scalar_pair_element_llvm_type(cx, 0), - layout.scalar_pair_element_llvm_type(cx, 1), + layout.scalar_pair_element_llvm_type(cx, 0, false), + layout.scalar_pair_element_llvm_type(cx, 1, false), ], false); } layout::Abi::Uninhabited | @@ -206,7 +206,7 @@ pub trait LayoutLlvmExt<'tcx> { fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: &layout::Scalar, offset: Size) -> Type; fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type; + index: usize, immediate: bool) -> Type; fn llvm_field_index(&self, index: usize) -> u64; fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option; @@ -340,7 +340,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type { + index: usize, immediate: bool) -> Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. match self.ty.sty { @@ -350,7 +350,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } ty::TyAdt(def, _) if def.is_box() => { let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index); + return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } _ => {} } @@ -361,14 +361,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { }; let scalar = [a, b][index]; - // Make sure to return the same type `immediate_llvm_type` would, - // to avoid dealing with two types and the associated conversions. - // This means that `(bool, bool)` is represented as `{i1, i1}`, - // both in memory and as an immediate, while `bool` is typically - // `i8` in memory and only `i1` when immediate. While we need to - // load/store `bool` as `i8` to avoid crippling LLVM optimizations, - // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`. - if scalar.is_bool() { + // Make sure to return the same type `immediate_llvm_type` would when + // dealing with an immediate pair. This means that `(bool, bool)` is + // effectively represented as `{i8, i8}` in memory and `{i1, i1}` as an + // immediate, just like `bool` is typically `i8` in memory and only `i1` + // when immediate. We need to load/store `bool` as `i8` to avoid + // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. + if immediate && scalar.is_bool() { return Type::i1(cx); } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index e3fa7a7db39..c027dece014 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -149,7 +149,7 @@ pub fn enum_id_1(x: Option>) -> Option> { x } -// CHECK: i16 @enum_id_2(i16) +// CHECK: { i8, i8 } @enum_id_2(i1 zeroext %x.0, i8 %x.1) #[no_mangle] pub fn enum_id_2(x: Option) -> Option { x diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs new file mode 100644 index 00000000000..2078a245085 --- /dev/null +++ b/src/test/codegen/scalar-pair-bool.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK: define { i8, i8 } @pair_bool_bool(i1 zeroext %pair.0, i1 zeroext %pair.1) +#[no_mangle] +pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) { + pair +} + +// CHECK: define { i8, i32 } @pair_bool_i32(i1 zeroext %pair.0, i32 %pair.1) +#[no_mangle] +pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) { + pair +} + +// CHECK: define { i32, i8 } @pair_i32_bool(i32 %pair.0, i1 zeroext %pair.1) +#[no_mangle] +pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { + pair +} + +// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1) +#[no_mangle] +pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { + // Make sure it can operate directly on the unpacked args + // CHECK: and i1 %arg0.0, %arg0.1 + // CHECK: or i1 %arg0.0, %arg0.1 + (a && b, a || b) +} -- cgit 1.4.1-3-g733a5 From 557736befc84fb72066128a8c42efe6e4e63a3b1 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 5 Jul 2018 14:22:09 -0700 Subject: Update scalar pairs per review comments --- src/librustc_codegen_llvm/mir/operand.rs | 6 +----- src/librustc_codegen_llvm/mir/place.rs | 6 +----- src/librustc_codegen_llvm/type_of.rs | 2 +- src/test/codegen/scalar-pair-bool.rs | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index 3069a155d1f..5d36eef99af 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::sync::Lrc; use base; -use common::{self, CodegenCx, C_null, C_undef, C_usize}; +use common::{CodegenCx, C_null, C_undef, C_usize}; use builder::{Builder, MemFlags}; use value::Value; use type_of::LayoutLlvmExt; @@ -310,10 +310,6 @@ impl<'a, 'tcx> OperandValue { OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { let llptr = bx.struct_gep(dest.llval, i as u64); - // Make sure to always store i1 as i8. - if common::val_ty(x) == Type::i1(bx.cx) { - assert_eq!(common::val_ty(llptr), Type::i8p(bx.cx)); - } let val = base::from_immediate(bx, x); bx.store_with_flags(val, llptr, dest.align, flags); } diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 36dcd04b02e..e7f9457a6a1 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; -use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big, val_ty}; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; use consts; use type_of::LayoutLlvmExt; use type_::Type; @@ -128,10 +128,6 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { let load = |i, scalar: &layout::Scalar| { let llptr = bx.struct_gep(self.llval, i as u64); - // Make sure to always load i1 as i8. - if scalar.is_bool() { - assert_eq!(val_ty(llptr), Type::i8p(bx.cx)); - } let load = bx.load(llptr, self.align); scalar_load_metadata(load, scalar); if scalar.is_bool() { diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 195f1c3b85a..0175d67803b 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -363,7 +363,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { // Make sure to return the same type `immediate_llvm_type` would when // dealing with an immediate pair. This means that `(bool, bool)` is - // effectively represented as `{i8, i8}` in memory and `{i1, i1}` as an + // effectively represented as `{i8, i8}` in memory and two `i1`s as an // immediate, just like `bool` is typically `i8` in memory and only `i1` // when immediate. We need to load/store `bool` as `i8` to avoid // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs index 2078a245085..f50e032f8e6 100644 --- a/src/test/codegen/scalar-pair-bool.rs +++ b/src/test/codegen/scalar-pair-bool.rs @@ -38,3 +38,17 @@ pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { // CHECK: or i1 %arg0.0, %arg0.1 (a && b, a || b) } + +// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1) +#[no_mangle] +pub fn pair_branches((a, b): (bool, bool)) { + // Make sure it can branch directly on the unpacked bool args + // CHECK: br i1 %arg0.0 + if a { + println!("Hello!"); + } + // CHECK: br i1 %arg0.1 + if b { + println!("Goodbye!"); + } +} -- cgit 1.4.1-3-g733a5 From 4ff90c7e0aa60cfab0d4fd5e52fcc63a7afd81c3 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 29 Jun 2018 10:28:51 +0200 Subject: bump minimum LLVM version to 5.0 --- .travis.yml | 2 +- src/bootstrap/native.rs | 6 +- src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile | 27 --- src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile | 27 +++ src/librustc_codegen_llvm/abi.rs | 6 +- src/librustc_codegen_llvm/mir/mod.rs | 22 +-- src/rustllvm/RustWrapper.cpp | 201 +-------------------- src/test/codegen/call-metadata.rs | 2 - src/test/codegen/issue-37945.rs | 1 - src/test/codegen/issue-45466.rs | 1 - src/test/codegen/mainsubprogram.rs | 1 - src/test/codegen/mainsubprogramstart.rs | 4 - src/test/codegen/noreturnflag.rs | 1 - src/test/codegen/stack-probes.rs | 1 - src/test/codegen/vtabletype.rs | 2 +- .../simd-intrinsic-generic-reduction.rs | 1 - src/test/mir-opt/lower_128bit_test.rs | 3 - src/test/run-make-fulldeps/cross-lang-lto/Makefile | 2 - .../llvm-pass/llvm-function-pass.so.cc | 7 +- .../llvm-pass/llvm-module-pass.so.cc | 7 +- src/test/run-pass/issue-40883.rs | 1 - .../run-pass/simd-intrinsic-generic-reduction.rs | 1 - src/test/run-pass/stack-probes-lto.rs | 1 - src/test/run-pass/stack-probes.rs | 1 - src/test/run-pass/thin-lto-global-allocator.rs | 1 - src/test/run-pass/thinlto/all-crates.rs | 1 - src/test/run-pass/thinlto/dylib-works.rs | 1 - src/test/run-pass/thinlto/msvc-imp-present.rs | 1 - src/test/run-pass/thinlto/thin-lto-inlines.rs | 1 - src/test/run-pass/thinlto/thin-lto-inlines2.rs | 1 - src/test/run-pass/thinlto/weak-works.rs | 1 - 31 files changed, 42 insertions(+), 293 deletions(-) delete mode 100644 src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile create mode 100644 src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile (limited to 'src/test/codegen') diff --git a/.travis.yml b/.travis.yml index ba8a39f355c..2cf10d76098 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: fast_finish: true include: # Images used in testing PR and try-build should be run first. - - env: IMAGE=x86_64-gnu-llvm-3.9 RUST_BACKTRACE=1 + - env: IMAGE=x86_64-gnu-llvm-5.0 RUST_BACKTRACE=1 if: type = pull_request OR branch = auto - env: IMAGE=dist-x86_64-linux DEPLOY=1 diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 93b8880a900..264acfacee6 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -256,12 +256,12 @@ fn check_llvm_version(builder: &Builder, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2) .filter_map(|s| s.parse::().ok()); - if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { - if major > 3 || (major == 3 && minor >= 9) { + if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { + if major >= 5 { return } } - panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version) + panic!("\n\nbad LLVM version: {}, need >=5.0\n\n", version) } fn configure_cmake(builder: &Builder, diff --git a/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile deleted file mode 100644 index 6b818604898..00000000000 --- a/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ - ca-certificates \ - python2.7 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-3.9-tools \ - libedit-dev \ - zlib1g-dev \ - xz-utils - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-3.9 \ - --enable-llvm-link-shared -ENV RUST_CHECK_TARGET check diff --git a/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile new file mode 100644 index 00000000000..4f90c509726 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-5.0-tools \ + libedit-dev \ + zlib1g-dev \ + xz-utils + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-5.0 \ + --enable-llvm-link-shared +ENV RUST_CHECK_TARGET check diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 6b5baa402b4..47c13919e6e 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -666,11 +666,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { layout::Int(..) if !scalar.is_bool() => { let range = scalar.valid_range_exclusive(bx.cx); if range.start != range.end { - // FIXME(nox): This causes very weird type errors about - // SHL operators in constants in stage 2 with LLVM 3.9. - if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { - bx.range_metadata(callsite, range); - } + bx.range_metadata(callsite, range); } } _ => {} diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs index f9be91b4f3f..608539dd3fa 100644 --- a/src/librustc_codegen_llvm/mir/mod.rs +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -22,7 +22,7 @@ use builder::Builder; use common::{CodegenCx, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::Instance; -use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode}; +use abi::{ArgTypeExt, FnType, FnTypeExt, PassMode}; use type_::Type; use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; @@ -430,10 +430,6 @@ fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, None }; - let deref_op = unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref()] - }; - mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; @@ -543,21 +539,11 @@ fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, if arg_index > 0 || mir.upvar_decls.is_empty() { // The Rust ABI passes indirect variables using a pointer and a manual copy, so we // need to insert a deref here, but the C ABI uses a pointer and a copy using the - // byval attribute, for which LLVM does the deref itself, so we must not add it. - // Starting with D31439 in LLVM 5, it *always* does the deref itself. - let mut variable_access = VariableAccess::DirectVariable { + // byval attribute, for which LLVM always does the deref itself, + // so we must not add it. + let variable_access = VariableAccess::DirectVariable { alloca: place.llval }; - if unsafe { llvm::LLVMRustVersionMajor() < 5 } { - if let PassMode::Indirect(ref attrs) = arg.mode { - if !attrs.contains(ArgAttribute::ByVal) { - variable_access = VariableAccess::IndirectVariable { - alloca: place.llval, - address_operations: &deref_op, - }; - } - } - } declare_local( bx, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index df8602d0803..2ac7a6a46ba 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -16,14 +16,8 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Bitcode/BitcodeWriterPass.h" - #include "llvm/IR/CallSite.h" - -#if LLVM_VERSION_GE(5, 0) #include "llvm/ADT/Optional.h" -#else -#include -#endif //===----------------------------------------------------------------------=== // @@ -176,14 +170,7 @@ extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index, LLVMRustAttribute RustAttr) { CallSite Call = CallSite(unwrap(Instr)); Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr)); -#if LLVM_VERSION_GE(5, 0) Call.addAttribute(Index, Attr); -#else - AttrBuilder B(Attr); - Call.setAttributes(Call.getAttributes().addAttributes( - Call->getContext(), Index, - AttributeSet::get(Call->getContext(), Index, B))); -#endif } extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, @@ -192,14 +179,8 @@ extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addAlignmentAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) Call.setAttributes(Call.getAttributes().addAttributes( Call->getContext(), Index, B)); -#else - Call.setAttributes(Call.getAttributes().addAttributes( - Call->getContext(), Index, - AttributeSet::get(Call->getContext(), Index, B))); -#endif } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, @@ -208,14 +189,8 @@ extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addDereferenceableAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) Call.setAttributes(Call.getAttributes().addAttributes( Call->getContext(), Index, B)); -#else - Call.setAttributes(Call.getAttributes().addAttributes( - Call->getContext(), Index, - AttributeSet::get(Call->getContext(), Index, B))); -#endif } extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, @@ -224,14 +199,8 @@ extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addDereferenceableOrNullAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) Call.setAttributes(Call.getAttributes().addAttributes( Call->getContext(), Index, B)); -#else - Call.setAttributes(Call.getAttributes().addAttributes( - Call->getContext(), Index, - AttributeSet::get(Call->getContext(), Index, B))); -#endif } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, @@ -239,11 +208,7 @@ extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, Function *A = unwrap(Fn); Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr)); AttrBuilder B(Attr); -#if LLVM_VERSION_GE(5, 0) A->addAttributes(Index, B); -#else - A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B)); -#endif } extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn, @@ -252,11 +217,7 @@ extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn, Function *A = unwrap(Fn); AttrBuilder B; B.addAlignmentAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) A->addAttributes(Index, B); -#else - A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B)); -#endif } extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, @@ -264,11 +225,7 @@ extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, Function *A = unwrap(Fn); AttrBuilder B; B.addDereferenceableAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) A->addAttributes(Index, B); -#else - A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B)); -#endif } extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn, @@ -277,11 +234,7 @@ extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn, Function *A = unwrap(Fn); AttrBuilder B; B.addDereferenceableOrNullAttr(Bytes); -#if LLVM_VERSION_GE(5, 0) A->addAttributes(Index, B); -#else - A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B)); -#endif } extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, @@ -291,11 +244,7 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name, Value); -#if LLVM_VERSION_GE(5, 0) F->addAttributes(Index, B); -#else - F->addAttributes(Index, AttributeSet::get(F->getContext(), Index, B)); -#endif } extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, @@ -305,12 +254,7 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); AttrBuilder B(Attr); auto PAL = F->getAttributes(); -#if LLVM_VERSION_GE(5, 0) auto PALNew = PAL.removeAttributes(F->getContext(), Index, B); -#else - const AttributeSet PALNew = PAL.removeAttributes( - F->getContext(), Index, AttributeSet::get(F->getContext(), Index, B)); -#endif F->setAttributes(PALNew); } @@ -360,7 +304,6 @@ enum class LLVMRustSynchronizationScope { CrossThread, }; -#if LLVM_VERSION_GE(5, 0) static SyncScope::ID fromRust(LLVMRustSynchronizationScope Scope) { switch (Scope) { case LLVMRustSynchronizationScope::SingleThread: @@ -371,18 +314,6 @@ static SyncScope::ID fromRust(LLVMRustSynchronizationScope Scope) { report_fatal_error("bad SynchronizationScope."); } } -#else -static SynchronizationScope fromRust(LLVMRustSynchronizationScope Scope) { - switch (Scope) { - case LLVMRustSynchronizationScope::SingleThread: - return SingleThread; - case LLVMRustSynchronizationScope::CrossThread: - return CrossThread; - default: - report_fatal_error("bad SynchronizationScope."); - } -} -#endif extern "C" LLVMValueRef LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order, @@ -422,18 +353,6 @@ extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) typedef DIBuilder *LLVMRustDIBuilderRef; -#if LLVM_VERSION_LT(5, 0) -typedef struct LLVMOpaqueMetadata *LLVMMetadataRef; - -namespace llvm { -DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef) - -inline Metadata **unwrap(LLVMMetadataRef *Vals) { - return reinterpret_cast(Vals); -} -} -#endif - template DIT *unwrapDIPtr(LLVMMetadataRef Ref) { return (DIT *)(Ref ? unwrap(Ref) : nullptr); } @@ -492,13 +411,8 @@ inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) { return static_cast(static_cast(F) & 0x3); } -#if LLVM_VERSION_GE(4, 0) static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) { DINode::DIFlags Result = DINode::DIFlags::FlagZero; -#else -static unsigned fromRust(LLVMRustDIFlags Flags) { - unsigned Result = 0; -#endif switch (visibility(Flags)) { case LLVMRustDIFlags::FlagPrivate: @@ -554,25 +468,18 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { Result |= DINode::DIFlags::FlagRValueReference; } -#if LLVM_VERSION_LE(4, 0) - if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) { - Result |= DINode::DIFlags::FlagExternalTypeRef; - } -#endif if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { Result |= DINode::DIFlags::FlagIntroducedVirtual; } if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { Result |= DINode::DIFlags::FlagBitField; } -#if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { Result |= DINode::DIFlags::FlagNoReturn; } if (isSet(Flags & LLVMRustDIFlags::FlagMainSubprogram)) { Result |= DINode::DIFlags::FlagMainSubprogram; } -#endif return Result; } @@ -612,14 +519,8 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( unsigned RuntimeVer, const char *SplitName) { auto *File = unwrapDI(FileRef); -#if LLVM_VERSION_GE(4, 0) return wrap(Builder->createCompileUnit(Lang, File, Producer, isOptimized, Flags, RuntimeVer, SplitName)); -#else - return wrap(Builder->createCompileUnit(Lang, File->getFilename(), - File->getDirectory(), Producer, isOptimized, - Flags, RuntimeVer, SplitName)); -#endif } extern "C" LLVMMetadataRef @@ -657,11 +558,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) { - return wrap(Builder->createBasicType(Name, SizeInBits, -#if LLVM_VERSION_LE(3, 9) - AlignInBits, -#endif - Encoding)); + return wrap(Builder->createBasicType(Name, SizeInBits, Encoding)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( @@ -669,9 +566,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) { return wrap(Builder->createPointerType(unwrapDI(PointeeTy), SizeInBits, AlignInBits, -#if LLVM_VERSION_GE(5, 0) /* DWARFAddressSpace */ None, -#endif Name)); } @@ -722,7 +617,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { llvm::GlobalVariable *InitVal = cast(unwrap(V)); -#if LLVM_VERSION_GE(4, 0) llvm::DIExpression *InitExpr = nullptr; if (llvm::ConstantInt *IntVal = llvm::dyn_cast(InitVal)) { InitExpr = Builder->createConstantValueExpression( @@ -741,12 +635,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( InitVal->setMetadata("dbg", VarExpr); return wrap(VarExpr); -#else - return wrap(Builder->createGlobalVariable( - unwrapDI(Context), Name, LinkageName, - unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, - InitVal, unwrapDIPtr(Decl))); -#endif } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( @@ -757,12 +645,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( unwrapDI(Scope), Name, unwrapDI(File), LineNo, - unwrapDI(Ty), AlwaysPreserve, fromRust(Flags) -#if LLVM_VERSION_GE(4, 0) - , - AlignInBits -#endif - )); + unwrapDI(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); } else { return wrap(Builder->createParameterVariable( unwrapDI(Scope), Name, ArgNo, unwrapDI(File), @@ -854,15 +737,8 @@ LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, LLVMMetadataRef File, unsigned LineNo) { return wrap(Builder->createNameSpace( - unwrapDI(Scope), Name -#if LLVM_VERSION_LT(5, 0) - , - unwrapDI(File), LineNo -#endif -#if LLVM_VERSION_GE(4, 0) - , + unwrapDI(Scope), Name, false // ExportSymbols (only relevant for C++ anonymous namespaces) -#endif )); } @@ -891,12 +767,7 @@ extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { } extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { -#if LLVM_VERSION_GE(5, 0) return dwarf::DW_OP_plus_uconst; -#else - // older LLVM used `plus` to behave like `plus_uconst`. - return dwarf::DW_OP_plus; -#endif } extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) { @@ -968,21 +839,12 @@ extern "C" void LLVMRustUnpackOptimizationDiagnostic( *FunctionOut = wrap(&Opt->getFunction()); RawRustStringOstream FilenameOS(FilenameOut); -#if LLVM_VERSION_GE(5,0) DiagnosticLocation loc = Opt->getLocation(); if (loc.isValid()) { *Line = loc.getLine(); *Column = loc.getColumn(); FilenameOS << loc.getFilename(); } -#else - const DebugLoc &loc = Opt->getDebugLoc(); - if (loc) { - *Line = loc.getLine(); - *Column = loc.getCol(); - FilenameOS << cast(loc.getScope())->getFilename(); - } -#endif RawRustStringOstream MessageOS(MessageOut); MessageOS << Opt->getMsg(); @@ -1402,7 +1264,6 @@ LLVMRustModuleCost(LLVMModuleRef M) { } // Vector reductions: -#if LLVM_VERSION_GE(5, 0) extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); @@ -1448,62 +1309,6 @@ LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); } -#else - -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef, bool) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef, bool) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef, bool) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef, bool) { - return nullptr; -} -#endif - -#if LLVM_VERSION_LT(4, 0) -extern "C" LLVMValueRef -LLVMBuildExactUDiv(LLVMBuilderRef B, LLVMValueRef LHS, - LLVMValueRef RHS, const char *Name) { - return wrap(unwrap(B)->CreateExactUDiv(unwrap(LHS), unwrap(RHS), Name)); -} -#endif - #if LLVM_VERSION_GE(6, 0) extern "C" LLVMValueRef LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { diff --git a/src/test/codegen/call-metadata.rs b/src/test/codegen/call-metadata.rs index 20d42ed852d..1b92ff60226 100644 --- a/src/test/codegen/call-metadata.rs +++ b/src/test/codegen/call-metadata.rs @@ -12,8 +12,6 @@ // scalar value. // compile-flags: -C no-prepopulate-passes -// min-llvm-version 4.0 - #![crate_type = "lib"] diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs index df02426badc..a36a50415ad 100644 --- a/src/test/codegen/issue-37945.rs +++ b/src/test/codegen/issue-37945.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// min-llvm-version 4.0 // compile-flags: -O // ignore-x86 // ignore-arm diff --git a/src/test/codegen/issue-45466.rs b/src/test/codegen/issue-45466.rs index 3702b675389..f916c1a0640 100644 --- a/src/test/codegen/issue-45466.rs +++ b/src/test/codegen/issue-45466.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// min-llvm-version 4.0 // compile-flags: -O #![crate_type="rlib"] diff --git a/src/test/codegen/mainsubprogram.rs b/src/test/codegen/mainsubprogram.rs index f0508bc90f2..2cfc20e30ca 100644 --- a/src/test/codegen/mainsubprogram.rs +++ b/src/test/codegen/mainsubprogram.rs @@ -14,7 +14,6 @@ // ignore-tidy-linelength // ignore-windows // ignore-macos -// min-llvm-version 4.0 // compile-flags: -g -C no-prepopulate-passes diff --git a/src/test/codegen/mainsubprogramstart.rs b/src/test/codegen/mainsubprogramstart.rs index 8325318f9af..62a996316c4 100644 --- a/src/test/codegen/mainsubprogramstart.rs +++ b/src/test/codegen/mainsubprogramstart.rs @@ -8,13 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This test depends on a patch that was committed to upstream LLVM -// before 4.0, formerly backported to the Rust LLVM fork. - // ignore-tidy-linelength // ignore-windows // ignore-macos -// min-llvm-version 4.0 // compile-flags: -g -C no-prepopulate-passes diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 7239223ca20..f66369782e5 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -10,7 +10,6 @@ // compile-flags: -g -C no-prepopulate-passes // ignore-tidy-linelength -// min-llvm-version 4.0 #![crate_type = "lib"] diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 6ab71723a1d..b8c2e62abef 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -21,7 +21,6 @@ // ignore-wasm // ignore-emscripten // ignore-windows -// min-system-llvm-version 5.0 // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/codegen/vtabletype.rs b/src/test/codegen/vtabletype.rs index b6466467548..abd1eb3e2cc 100644 --- a/src/test/codegen/vtabletype.rs +++ b/src/test/codegen/vtabletype.rs @@ -14,7 +14,7 @@ // ignore-tidy-linelength // ignore-windows // ignore-macos -// min-system-llvm-version 5.1 +// min-llvm-version 6.0 // compile-flags: -g -C no-prepopulate-passes diff --git a/src/test/compile-fail/simd-intrinsic-generic-reduction.rs b/src/test/compile-fail/simd-intrinsic-generic-reduction.rs index 57e4bb76a6c..725960a866b 100644 --- a/src/test/compile-fail/simd-intrinsic-generic-reduction.rs +++ b/src/test/compile-fail/simd-intrinsic-generic-reduction.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// min-llvm-version 5.0 // ignore-emscripten // Test that the simd_reduce_{op} intrinsics produce ok-ish error diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 27446d6bd28..b4b54e13a69 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// asmjs can't even pass i128 as arguments or return values, so ignore it. -// this will hopefully be fixed by the LLVM 5 upgrade (#43370) -// ignore-asmjs // ignore-emscripten // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no diff --git a/src/test/run-make-fulldeps/cross-lang-lto/Makefile b/src/test/run-make-fulldeps/cross-lang-lto/Makefile index cdc429d1f99..efe1b7072ff 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto/Makefile @@ -1,5 +1,3 @@ - -# min-llvm-version 4.0 # ignore-msvc -include ../tools.mk diff --git a/src/test/run-make-fulldeps/llvm-pass/llvm-function-pass.so.cc b/src/test/run-make-fulldeps/llvm-pass/llvm-function-pass.so.cc index 880c9bce562..c0a17d920cf 100644 --- a/src/test/run-make-fulldeps/llvm-pass/llvm-function-pass.so.cc +++ b/src/test/run-make-fulldeps/llvm-pass/llvm-function-pass.so.cc @@ -28,12 +28,7 @@ namespace { bool runOnFunction(Function &F) override; -#if LLVM_VERSION_MAJOR >= 4 - StringRef -#else - const char * -#endif - getPassName() const override { + StringRef getPassName() const override { return "Some LLVM pass"; } diff --git a/src/test/run-make-fulldeps/llvm-pass/llvm-module-pass.so.cc b/src/test/run-make-fulldeps/llvm-pass/llvm-module-pass.so.cc index 280eca7e8f0..70051681ab0 100644 --- a/src/test/run-make-fulldeps/llvm-pass/llvm-module-pass.so.cc +++ b/src/test/run-make-fulldeps/llvm-pass/llvm-module-pass.so.cc @@ -27,12 +27,7 @@ namespace { bool runOnModule(Module &M) override; -#if LLVM_VERSION_MAJOR >= 4 - StringRef -#else - const char * -#endif - getPassName() const override { + StringRef getPassName() const override { return "Some LLVM pass"; } diff --git a/src/test/run-pass/issue-40883.rs b/src/test/run-pass/issue-40883.rs index feb4a88a1d1..c1f3b2028aa 100644 --- a/src/test/run-pass/issue-40883.rs +++ b/src/test/run-pass/issue-40883.rs @@ -9,7 +9,6 @@ // except according to those terms. // check that we don't have linear stack usage with multiple calls to `push` -// min-llvm-version 4.0 #![feature(test)] diff --git a/src/test/run-pass/simd-intrinsic-generic-reduction.rs b/src/test/run-pass/simd-intrinsic-generic-reduction.rs index 9a1214d3b35..8e999b7115e 100644 --- a/src/test/run-pass/simd-intrinsic-generic-reduction.rs +++ b/src/test/run-pass/simd-intrinsic-generic-reduction.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// min-llvm-version 5.0 // ignore-emscripten // Test that the simd_reduce_{op} intrinsics produce the correct results. diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index 3fef19c51bd..ff5413ce06c 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -21,7 +21,6 @@ // ignore-emscripten no processes // ignore-musl FIXME #31506 // ignore-pretty -// min-system-llvm-version 5.0 // compile-flags: -C lto // no-prefer-dynamic diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index c93dcf01939..1334ab8dc63 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -20,7 +20,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-musl FIXME #31506 -// min-system-llvm-version 5.0 use std::mem; use std::process::Command; diff --git a/src/test/run-pass/thin-lto-global-allocator.rs b/src/test/run-pass/thin-lto-global-allocator.rs index 3a0e2fe01db..257d5bbc306 100644 --- a/src/test/run-pass/thin-lto-global-allocator.rs +++ b/src/test/run-pass/thin-lto-global-allocator.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: -Z thinlto -C codegen-units=2 -// min-llvm-version 4.0 #[global_allocator] static A: std::alloc::System = std::alloc::System; diff --git a/src/test/run-pass/thinlto/all-crates.rs b/src/test/run-pass/thinlto/all-crates.rs index 772a9ec8293..8d68202d711 100644 --- a/src/test/run-pass/thinlto/all-crates.rs +++ b/src/test/run-pass/thinlto/all-crates.rs @@ -10,7 +10,6 @@ // compile-flags: -Clto=thin // no-prefer-dynamic -// min-llvm-version 4.0 fn main() { println!("hello!"); diff --git a/src/test/run-pass/thinlto/dylib-works.rs b/src/test/run-pass/thinlto/dylib-works.rs index 3f54519d0d8..06df40f6142 100644 --- a/src/test/run-pass/thinlto/dylib-works.rs +++ b/src/test/run-pass/thinlto/dylib-works.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:dylib.rs -// min-llvm-version 4.0 extern crate dylib; diff --git a/src/test/run-pass/thinlto/msvc-imp-present.rs b/src/test/run-pass/thinlto/msvc-imp-present.rs index 8329c7032f1..95cff2a2862 100644 --- a/src/test/run-pass/thinlto/msvc-imp-present.rs +++ b/src/test/run-pass/thinlto/msvc-imp-present.rs @@ -10,7 +10,6 @@ // aux-build:msvc-imp-present.rs // compile-flags: -Z thinlto -C codegen-units=8 -// min-llvm-version: 4.0 // no-prefer-dynamic // On MSVC we have a "hack" where we emit symbols that look like `_imp_$name` diff --git a/src/test/run-pass/thinlto/thin-lto-inlines.rs b/src/test/run-pass/thinlto/thin-lto-inlines.rs index 7a71dd2bc51..41ca983af51 100644 --- a/src/test/run-pass/thinlto/thin-lto-inlines.rs +++ b/src/test/run-pass/thinlto/thin-lto-inlines.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: -Z thinlto -C codegen-units=8 -O -// min-llvm-version 4.0 // ignore-emscripten can't inspect instructions on emscripten // We want to assert here that ThinLTO will inline across codegen units. There's diff --git a/src/test/run-pass/thinlto/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs index 6020f72415d..3c0e904662a 100644 --- a/src/test/run-pass/thinlto/thin-lto-inlines2.rs +++ b/src/test/run-pass/thinlto/thin-lto-inlines2.rs @@ -10,7 +10,6 @@ // compile-flags: -C codegen-units=8 -O -C lto=thin // aux-build:thin-lto-inlines-aux.rs -// min-llvm-version 4.0 // no-prefer-dynamic // ignore-emscripten can't inspect instructions on emscripten diff --git a/src/test/run-pass/thinlto/weak-works.rs b/src/test/run-pass/thinlto/weak-works.rs index b9719e04f34..0a1b7307a46 100644 --- a/src/test/run-pass/thinlto/weak-works.rs +++ b/src/test/run-pass/thinlto/weak-works.rs @@ -10,7 +10,6 @@ // compile-flags: -C codegen-units=8 -Z thinlto // ignore-windows -// min-llvm-version 4.0 #![feature(linkage)] -- cgit 1.4.1-3-g733a5 From 52d774027793bdad2122b6cc34cec68a8b6a9626 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 2 Jul 2018 11:13:34 +0200 Subject: bump llvm version of failing codegen test --- src/test/codegen/issue-45466.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/issue-45466.rs b/src/test/codegen/issue-45466.rs index f916c1a0640..14954763944 100644 --- a/src/test/codegen/issue-45466.rs +++ b/src/test/codegen/issue-45466.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: -O +// min-llvm-version 6.0 #![crate_type="rlib"] -- cgit 1.4.1-3-g733a5 From 42eb85002ae4bda9899216805d03fa7d77279ede Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 1 Jun 2018 10:20:00 -0700 Subject: Upgrade to LLVM's master branch (LLVM 7) This commit upgrades the main LLVM submodule to LLVM's current master branch. The LLD submodule is updated in tandem as well as compiler-builtins. Along the way support was also added for LLVM 7's new features. This primarily includes the support for custom section concatenation natively in LLD so we now add wasm custom sections in LLVM IR rather than having custom support in rustc itself for doing so. Some other miscellaneous changes are: * We now pass `--gc-sections` to `wasm-ld` * The optimization level is now passed to `wasm-ld` * A `--stack-first` option is passed to LLD to have stack overflow always cause a trap instead of corrupting static data * The wasm target for LLVM switched to `wasm32-unknown-unknown`. * The syntax for aligned pointers has changed in LLVM IR and tests are updated to reflect this. * The `thumbv6m-none-eabi` target is disabled due to an [LLVM bug][llbug] Nowadays we've been mostly only upgrading whenever there's a major release of LLVM but enough changes have been happening on the wasm target that there's been growing motivation for quite some time now to upgrade out version of LLD. To upgrade LLD, however, we need to upgrade LLVM to avoid needing to build yet another version of LLVM on the builders. The revision of LLVM in use here is arbitrarily chosen. We will likely need to continue to update it over time if and when we discover bugs. Once LLVM 7 is fully released we can switch to that channel as well. [llbug]: https://bugs.llvm.org/show_bug.cgi?id=37382 --- src/libcompiler_builtins | 2 +- src/librustc/dep_graph/dep_node.rs | 2 - src/librustc/hir/check_attr.rs | 7 +-- src/librustc/hir/mod.rs | 2 + src/librustc/ich/impls_hir.rs | 1 + src/librustc/mir/mono.rs | 8 ++- src/librustc/ty/query/config.rs | 6 --- src/librustc/ty/query/mod.rs | 1 - src/librustc/ty/query/plumbing.rs | 1 - src/librustc_codegen_llvm/attributes.rs | 31 +----------- src/librustc_codegen_llvm/back/link.rs | 6 +-- src/librustc_codegen_llvm/back/linker.rs | 37 +++++++++++++- src/librustc_codegen_llvm/back/wasm.rs | 42 +-------------- src/librustc_codegen_llvm/base.rs | 59 +++++++++++----------- src/librustc_codegen_llvm/lib.rs | 4 +- src/librustc_codegen_llvm/mono_item.rs | 7 +++ src/librustc_codegen_utils/codegen_backend.rs | 1 - src/librustc_metadata/cstore_impl.rs | 2 - src/librustc_metadata/decoder.rs | 10 ---- src/librustc_metadata/encoder.rs | 12 ----- src/librustc_metadata/schema.rs | 1 - src/librustc_mir/monomorphize/collector.rs | 10 ++++ src/librustc_mir/monomorphize/item.rs | 18 +++++-- src/librustc_mir/monomorphize/partitioning.rs | 7 ++- src/librustc_target/spec/wasm32_unknown_unknown.rs | 2 +- src/librustc_typeck/collect.rs | 8 +++ src/librustdoc/fold.rs | 9 ++-- src/llvm | 2 +- src/rustllvm/PassWrapper.cpp | 4 ++ src/test/codegen/align-struct.rs | 3 +- src/test/codegen/consts.rs | 5 +- src/test/codegen/packed.rs | 14 ++--- src/test/codegen/repeat-trusted-len.rs | 3 +- src/test/codegen/simd-intrinsic-float-minmax.rs | 15 +++--- src/test/codegen/stores.rs | 6 ++- src/test/run-make-fulldeps/pgo-gen-lto/Makefile | 2 + src/test/run-make-fulldeps/pgo-gen/Makefile | 2 + src/test/run-pass/simd-intrinsic-float-math.rs | 46 ++++++++++++----- src/tools/lld | 2 +- 39 files changed, 202 insertions(+), 198 deletions(-) (limited to 'src/test/codegen') diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 4cfd7101eb5..86bf357a14c 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 4cfd7101eb549169cdaeda5313f7c39415b9d736 +Subproject commit 86bf357a14cacb4a4169455e729d409b5ecc1da0 diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3c4472aef6b..ef564ac89f9 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -665,8 +665,6 @@ define_dep_nodes!( <'tcx> [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, - [] WasmCustomSections(CrateNum), - [input] Features, [] ProgramClausesFor(DefId), diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index c71b47fa4e1..2d83c158fe0 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -57,7 +57,7 @@ struct CheckAttrVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { /// Check any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { - if target == Target::Fn { + if target == Target::Fn || target == Target::Const { self.tcx.codegen_fn_attrs(self.tcx.hir.local_def_id(item.id)); } else if let Some(a) = item.attrs.iter().find(|a| a.check_name("target_feature")) { self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function") @@ -85,11 +85,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { if target != Target::Const { self.tcx.sess.span_err(attr.span, "only allowed on consts"); } - - if attr.value_str().is_none() { - self.tcx.sess.span_err(attr.span, "must be of the form \ - #[wasm_custom_section = \"foo\"]"); - } } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 8d83dd3279c..2a515fe3f2d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2259,6 +2259,7 @@ pub struct CodegenFnAttrs { pub export_name: Option, pub target_features: Vec, pub linkage: Option, + pub wasm_custom_section: Option, } bitflags! { @@ -2283,6 +2284,7 @@ impl CodegenFnAttrs { export_name: None, target_features: vec![], linkage: None, + wasm_custom_section: None, } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 8b62ba119eb..b6add3e6f12 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1120,6 +1120,7 @@ impl_stable_hash_for!(struct hir::CodegenFnAttrs { export_name, target_features, linkage, + wasm_custom_section, }); impl<'hir> HashStable> for hir::CodegenFnAttrFlags diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 9de9347d0ce..79566fbbc11 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -24,6 +24,7 @@ pub enum MonoItem<'tcx> { Fn(Instance<'tcx>), Static(DefId), GlobalAsm(NodeId), + CustomSection(DefId), } impl<'tcx> MonoItem<'tcx> { @@ -36,7 +37,9 @@ impl<'tcx> MonoItem<'tcx> { }, // Conservatively estimate the size of a static declaration // or assembly to be 1. - MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, + MonoItem::Static(_) | + MonoItem::GlobalAsm(_) | + MonoItem::CustomSection(_) => 1, } } } @@ -51,7 +54,8 @@ impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { MonoItem::Fn(ref instance) => { instance.hash_stable(hcx, hasher); } - MonoItem::Static(def_id) => { + MonoItem::Static(def_id) | + MonoItem::CustomSection(def_id) => { def_id.hash_stable(hcx, hasher); } MonoItem::GlobalAsm(node_id) => { diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 229caeb95d6..bd6217e28c7 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -776,12 +776,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> } } -impl<'tcx> QueryDescription<'tcx> for queries::wasm_custom_sections<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("custom wasm sections for a crate") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 9ad93b4d5e2..3581dd87f6f 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -546,7 +546,6 @@ define_queries! { <'tcx> ty::ParamEnv<'tcx> ) -> Clauses<'tcx>, - [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc>, [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) -> Lrc>, } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 9f802f7fdcd..9dc8321f825 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1208,7 +1208,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::Features => { force!(features_query, LOCAL_CRATE); } DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } - DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } DepKind::ForeignModules => { force!(foreign_modules, krate!()); } diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 429acbbe0c2..8246bb24366 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -11,9 +11,8 @@ use std::ffi::{CStr, CString}; -use rustc::hir::{self, CodegenFnAttrFlags}; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; @@ -222,37 +221,9 @@ pub fn provide(providers: &mut Providers) { } }; - providers.wasm_custom_sections = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - let mut finder = WasmSectionFinder { tcx, list: Vec::new() }; - tcx.hir.krate().visit_all_item_likes(&mut finder); - Lrc::new(finder.list) - }; - provide_extern(providers); } -struct WasmSectionFinder<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - list: Vec, -} - -impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item) { - match i.node { - hir::ItemConst(..) => {} - _ => return, - } - if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) { - self.list.push(self.tcx.hir.local_def_id(i.id)); - } - } - - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {} - - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} -} - pub fn provide_extern(providers: &mut Providers) { providers.wasm_import_module_map = |tcx, cnum| { let mut ret = FxHashMap(); diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 70053cb7e9d..e8636b1c999 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -29,7 +29,7 @@ use rustc::util::common::time; use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; use tempfile::{Builder as TempFileBuilder, TempDir}; -use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor, TargetTriple}; +use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; use rustc_data_structures::fx::FxHashSet; use context::get_reloc_model; use llvm; @@ -837,10 +837,8 @@ fn link_natively(sess: &Session, } } - if sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown") { + if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { wasm::rewrite_imports(&out_filename, &codegen_results.crate_info.wasm_imports); - wasm::add_custom_sections(&out_filename, - &codegen_results.crate_info.wasm_custom_sections); } } diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 99249255d27..f07c758807e 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -86,6 +86,7 @@ impl LinkerInfo { LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd { cmd, + sess, }) as Box } } @@ -919,11 +920,12 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { symbols } -pub struct WasmLd { +pub struct WasmLd<'a> { cmd: Command, + sess: &'a Session, } -impl Linker for WasmLd { +impl<'a> Linker for WasmLd<'a> { fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } @@ -988,9 +990,20 @@ impl Linker for WasmLd { } fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("--gc-sections"); } fn optimize(&mut self) { + self.cmd.arg(match self.sess.opts.optimize { + OptLevel::No => "-O0", + OptLevel::Less => "-O1", + OptLevel::Default => "-O2", + OptLevel::Aggressive => "-O3", + // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` + // instead. + OptLevel::Size => "-O2", + OptLevel::SizeMin => "-O2" + }); } fn pgo_gen(&mut self) { @@ -1020,8 +1033,28 @@ impl Linker for WasmLd { // this isn't yet the bottleneck of compilation at all anyway. self.cmd.arg("--no-threads"); + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. self.cmd.arg("-z").arg("stack-size=1048576"); + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + self.cmd.arg("--stack-first"); + // FIXME we probably shouldn't pass this but instead pass an explicit // whitelist of symbols we'll allow to be undefined. Unfortunately // though we can't handle symbols like `log10` that LLVM injects at a diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs index c553eca08e6..d378d5af1c0 100644 --- a/src/librustc_codegen_llvm/back/wasm.rs +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::BTreeMap; use std::fs; use std::path::Path; use std::str; @@ -24,45 +23,6 @@ const WASM_EXTERNAL_KIND_TABLE: u8 = 1; const WASM_EXTERNAL_KIND_MEMORY: u8 = 2; const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3; -/// Append all the custom sections listed in `sections` to the wasm binary -/// specified at `path`. -/// -/// LLVM 6 which we're using right now doesn't have the ability to create custom -/// sections in wasm files nor does LLD have the ability to merge these sections -/// into one larger section when linking. It's expected that this will -/// eventually get implemented, however! -/// -/// Until that time though this is a custom implementation in rustc to append -/// all sections to a wasm file to the finished product that LLD produces. -/// -/// Support for this is landing in LLVM in https://reviews.llvm.org/D43097, -/// although after that support will need to be in LLD as well. -pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { - if sections.len() == 0 { - return - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - - // see https://webassembly.github.io/spec/core/binary/modules.html#custom-section - let mut wasm = WasmEncoder { data: wasm }; - for (section, bytes) in sections { - // write the `id` identifier, 0 for a custom section - wasm.byte(0); - - // figure out how long our name descriptor will be - let mut name = WasmEncoder::new(); - name.str(section); - - // write the length of the payload followed by all its contents - wasm.u32((bytes.len() + name.data.len()) as u32); - wasm.data.extend_from_slice(&name.data); - wasm.data.extend_from_slice(bytes); - } - - fs::write(path, &wasm.data).expect("failed to write wasm output"); -} - /// Rewrite the module imports are listed from in a wasm module given the field /// name to module name mapping in `import_map`. /// @@ -80,7 +40,7 @@ pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { /// /// Support for this was added to LLVM in /// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still -/// needs to be added (AFAIK at the time of this writing) to LLD +/// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168 pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { if import_map.len() == 0 { return diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index f9d84319433..70b66dd436b 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -33,6 +33,7 @@ use back::link; use back::write::{self, OngoingCodegen, create_target_machine}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; +use libc::c_uint; use metadata; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::middle::lang_items::StartFnLangItem; @@ -74,10 +75,8 @@ use type_of::LayoutLlvmExt; use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use rustc_data_structures::sync::Lrc; -use rustc_target::spec::TargetTriple; use std::any::Any; -use std::collections::BTreeMap; use std::ffi::CString; use std::str; use std::sync::Arc; @@ -1095,7 +1094,6 @@ impl CrateInfo { used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), used_crate_source: FxHashMap(), - wasm_custom_sections: BTreeMap::new(), wasm_imports: FxHashMap(), lang_item_to_crate: FxHashMap(), missing_lang_items: FxHashMap(), @@ -1105,16 +1103,9 @@ impl CrateInfo { let load_wasm_items = tcx.sess.crate_types.borrow() .iter() .any(|c| *c != config::CrateTypeRlib) && - tcx.sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown"); + tcx.sess.opts.target_triple.triple() == "wasm32-unknown-unknown"; if load_wasm_items { - info!("attempting to load all wasm sections"); - for &id in tcx.wasm_custom_sections(LOCAL_CRATE).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } info.load_wasm_imports(tcx, LOCAL_CRATE); } @@ -1138,12 +1129,6 @@ impl CrateInfo { info.is_no_builtins.insert(cnum); } if load_wasm_items { - for &id in tcx.wasm_custom_sections(cnum).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } info.load_wasm_imports(tcx, cnum); } let missing = tcx.missing_lang_items(cnum); @@ -1380,25 +1365,41 @@ mod temp_stable_hash_impls { } } -fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { +pub fn define_custom_section(cx: &CodegenCx, def_id: DefId) { use rustc::mir::interpret::GlobalId; - info!("loading wasm section {:?}", id); + assert!(cx.tcx.sess.opts.target_triple.triple().starts_with("wasm32")); + + info!("loading wasm section {:?}", def_id); - let section = tcx.get_attrs(id) - .iter() - .find(|a| a.check_name("wasm_custom_section")) - .expect("missing #[wasm_custom_section] attribute") - .value_str() - .expect("malformed #[wasm_custom_section] attribute"); + let section = cx.tcx.codegen_fn_attrs(def_id).wasm_custom_section.unwrap(); - let instance = ty::Instance::mono(tcx, id); + let instance = ty::Instance::mono(cx.tcx, def_id); let cid = GlobalId { instance, promoted: None }; let param_env = ty::ParamEnv::reveal_all(); - let val = tcx.const_eval(param_env.and(cid)).unwrap(); - let alloc = tcx.const_value_to_allocation(val); - (section.to_string(), alloc.bytes.clone()) + let val = cx.tcx.const_eval(param_env.and(cid)).unwrap(); + let alloc = cx.tcx.const_value_to_allocation(val); + + unsafe { + let section = llvm::LLVMMDStringInContext( + cx.llcx, + section.as_str().as_ptr() as *const _, + section.as_str().len() as c_uint, + ); + let alloc = llvm::LLVMMDStringInContext( + cx.llcx, + alloc.bytes.as_ptr() as *const _, + alloc.bytes.len() as c_uint, + ); + let data = [section, alloc]; + let meta = llvm::LLVMMDNodeInContext(cx.llcx, data.as_ptr(), 2); + llvm::LLVMAddNamedMetadataOperand( + cx.llmod, + "wasm.custom_sections\0".as_ptr() as *const _, + meta, + ); + } } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 93d9ce1e98a..a2f28417520 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -65,7 +65,6 @@ pub use llvm_util::target_features; use std::any::Any; use std::path::PathBuf; use std::sync::mpsc; -use std::collections::BTreeMap; use rustc_data_structures::sync::Lrc; use rustc::dep_graph::DepGraph; @@ -94,7 +93,7 @@ mod back { pub mod symbol_export; pub mod write; mod rpath; - mod wasm; + pub mod wasm; } mod abi; @@ -382,7 +381,6 @@ struct CrateInfo { used_crate_source: FxHashMap>, used_crates_static: Vec<(CrateNum, LibSource)>, used_crates_dynamic: Vec<(CrateNum, LibSource)>, - wasm_custom_sections: BTreeMap>, wasm_imports: FxHashMap, lang_item_to_crate: FxHashMap, missing_lang_items: FxHashMap>, diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 2f7b27b85af..e142a7d9c1c 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -66,6 +66,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") } } + MonoItem::CustomSection(def_id) => { + base::define_custom_section(cx, def_id); + } MonoItem::Fn(instance) => { base::codegen_instance(&cx, instance); } @@ -97,6 +100,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { MonoItem::Fn(instance) => { predefine_fn(cx, instance, linkage, visibility, &symbol_name); } + MonoItem::CustomSection(..) => {} MonoItem::GlobalAsm(..) => {} } @@ -116,6 +120,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { MonoItem::Static(id) => { format!("Static({:?})", id) } + MonoItem::CustomSection(id) => { + format!("CustomSection({:?})", id) + } MonoItem::GlobalAsm(id) => { format!("GlobalAsm({:?})", id) } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 3cbf176d98b..57e6c0d7b85 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -137,7 +137,6 @@ impl CodegenBackend for MetadataOnlyCodegenBackend { }; providers.is_reachable_non_generic = |_tcx, _defid| true; providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new()); - providers.wasm_custom_sections = |_tcx, _crate| Lrc::new(Vec::new()); } fn provide_extern(&self, providers: &mut Providers) { providers.is_reachable_non_generic = |_tcx, _defid| true; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 20d9121668b..cded812b5f0 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -266,8 +266,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, Arc::new(cdata.exported_symbols(tcx)) } - - wasm_custom_sections => { Lrc::new(cdata.wasm_custom_sections()) } } pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d604ac819b8..38149d1ca50 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1011,16 +1011,6 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn wasm_custom_sections(&self) -> Vec { - let sections = self.root - .wasm_custom_sections - .decode(self) - .map(|def_index| self.local_def_id(def_index)) - .collect::>(); - info!("loaded wasm sections {:?}", sections); - return sections - } - pub fn get_macro(&self, id: DefIndex) -> (InternedString, MacroDef) { let entry = self.entry(id); match entry.kind { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 36f053e5aa9..72f91dcea60 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -436,12 +436,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { &exported_symbols); let exported_symbols_bytes = self.position() - i; - // encode wasm custom sections - let wasm_custom_sections = self.tcx.wasm_custom_sections(LOCAL_CRATE); - let wasm_custom_sections = self.tracked( - IsolatedEncoder::encode_wasm_custom_sections, - &wasm_custom_sections); - let tcx = self.tcx; // Encode the items. @@ -527,7 +521,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { def_path_table, impls, exported_symbols, - wasm_custom_sections, interpret_alloc_index, index, }); @@ -1543,11 +1536,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } - fn encode_wasm_custom_sections(&mut self, statics: &[DefId]) -> LazySeq { - info!("encoding custom wasm section constants {:?}", statics); - self.lazy_seq(statics.iter().map(|id| id.index)) - } - fn encode_dylib_dependency_formats(&mut self, _: ()) -> LazySeq> { match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { Some(arr) => { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index a0b21e63ac5..430cbf9b529 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -206,7 +206,6 @@ pub struct CrateRoot { pub def_path_table: Lazy, pub impls: LazySeq, pub exported_symbols: EncodedExportedSymbols, - pub wasm_custom_sections: LazySeq, pub interpret_alloc_index: LazySeq, pub index: LazySeq, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 09c5df00052..ce917b8ca55 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -414,6 +414,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::GlobalAsm(..) => { recursion_depth_reset = None; } + MonoItem::CustomSection(..) => { + recursion_depth_reset = None; + } } record_accesses(tcx, starting_point, &neighbors[..], inlining_map); @@ -990,6 +993,13 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemConst(..) => { // const items only generate mono items if they are // actually used somewhere. Just declaring them is insufficient. + + let def_id = self.tcx.hir.local_def_id(item.id); + if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") && + self.tcx.codegen_fn_attrs(def_id).wasm_custom_section.is_some() + { + self.output.push(MonoItem::CustomSection(def_id)); + } } hir::ItemFn(..) => { let def_id = self.tcx.hir.local_def_id(item.id); diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 0428489fd8d..1389ad63c3a 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -63,6 +63,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { instance.substs.types().next().is_some() } MonoItem::Static(..) | + MonoItem::CustomSection(..) | MonoItem::GlobalAsm(..) => false, } } @@ -73,6 +74,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::Static(def_id) => { tcx.symbol_name(Instance::mono(tcx, def_id)) } + MonoItem::CustomSection(def_id) => { + tcx.symbol_name(Instance::mono(tcx, def_id)) + } MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); ty::SymbolName { @@ -121,9 +125,8 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } } } - MonoItem::Static(..) => { - InstantiationMode::GloballyShared { may_conflict: false } - } + MonoItem::Static(..) | + MonoItem::CustomSection(..) | MonoItem::GlobalAsm(..) => { InstantiationMode::GloballyShared { may_conflict: false } } @@ -134,6 +137,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { let def_id = match *self.as_mono_item() { MonoItem::Fn(ref instance) => instance.def_id(), MonoItem::Static(def_id) => def_id, + MonoItem::CustomSection(..) => return None, MonoItem::GlobalAsm(..) => return None, }; @@ -171,6 +175,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { let (def_id, substs) = match *self.as_mono_item() { MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), MonoItem::Static(def_id) => (def_id, Substs::empty()), + MonoItem::CustomSection(..) => return true, // global asm never has predicates MonoItem::GlobalAsm(..) => return true }; @@ -187,6 +192,10 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, + MonoItem::CustomSection(def_id) => { + let instance = Instance::new(def_id, tcx.intern_substs(&[])); + to_string_internal(tcx, "custom-section ", instance) + }, MonoItem::GlobalAsm(..) => { "global_asm".to_string() } @@ -212,6 +221,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::Static(def_id) => { tcx.hir.as_local_node_id(def_id) } + MonoItem::CustomSection(def_id) => { + tcx.hir.as_local_node_id(def_id) + } MonoItem::GlobalAsm(node_id) => { Some(node_id) } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f83ea6fa13b..5f15870d6fb 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -180,7 +180,8 @@ pub trait CodegenUnitExt<'tcx> { } } } - MonoItem::Static(def_id) => { + MonoItem::Static(def_id) | + MonoItem::CustomSection(def_id) => { tcx.hir.as_local_node_id(def_id) } MonoItem::GlobalAsm(node_id) => { @@ -449,6 +450,9 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; (Linkage::External, visibility) } + MonoItem::CustomSection(..) => { + (Linkage::External, Visibility::Hidden) + } MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_reachable_non_generic(def_id) { @@ -714,6 +718,7 @@ fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Some(def_id) } MonoItem::Static(def_id) => Some(def_id), + MonoItem::CustomSection(def_id) => Some(def_id), MonoItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_target/spec/wasm32_unknown_unknown.rs b/src/librustc_target/spec/wasm32_unknown_unknown.rs index 6f51495bae9..51d402e197d 100644 --- a/src/librustc_target/spec/wasm32_unknown_unknown.rs +++ b/src/librustc_target/spec/wasm32_unknown_unknown.rs @@ -57,7 +57,7 @@ pub fn target() -> Result { .. Default::default() }; Ok(Target { - llvm_target: "wasm32-unknown-unknown-wasm".to_string(), + llvm_target: "wasm32-unknown-unknown".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 94b17532cb7..fa2f9885964 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1925,6 +1925,14 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen if let Some(val) = attr.value_str() { codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); } + } else if attr.check_name("wasm_custom_section") { + match attr.value_str() { + Some(name) => codegen_fn_attrs.wasm_custom_section = Some(name), + None => { + tcx.sess.span_err(attr.span, "must be of the form \ + #[wasm_custom_section = \"foo\"]"); + } + } } } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 54c57c9ac6e..8e8566cbbde 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::mem; + use clean::*; pub enum FoldItem { @@ -109,12 +111,13 @@ pub trait DocFolder : Sized { } fn fold_crate(&mut self, mut c: Crate) -> Crate { - c.module = c.module.and_then(|module| self.fold_item(module)); + c.module = c.module.take().and_then(|module| self.fold_item(module)); - c.external_traits = c.external_traits.into_iter().map(|(k, mut v)| { + let traits = mem::replace(&mut c.external_traits, Default::default()); + c.external_traits.extend(traits.into_iter().map(|(k, mut v)| { v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); (k, v) - }).collect(); + })); c } } diff --git a/src/llvm b/src/llvm index 509f29ac178..03684905101 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 509f29ac17874394acf4d49d6bae3cd93c652aa1 +Subproject commit 03684905101f0b7e49dfe530e54dc1aeac6ef0fb diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index d5410feb254..a00ff3b345d 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -545,7 +545,11 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, return LLVMRustResult::Failure; } +#if LLVM_VERSION_GE(7, 0) + unwrap(Target)->addPassesToEmitFile(*PM, OS, nullptr, FileType, false); +#else unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); +#endif PM->run(*unwrap(M)); // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index f306608f432..bf119da2e82 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -10,6 +10,7 @@ // compile-flags: -C no-prepopulate-passes // ignore-tidy-linelength +// min-llvm-version 7.0 #![crate_type = "lib"] @@ -42,7 +43,7 @@ pub enum Enum64 { #[no_mangle] pub fn align64(i : i32) -> Align64 { // CHECK: %a64 = alloca %Align64, align 64 -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 64, i32 64, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 64 %{{.*}}, i8* align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) let a64 = Align64(i); a64 } diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 007fb7f4596..30fffbb769b 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -10,6 +10,7 @@ // compile-flags: -C no-prepopulate-passes // ignore-tidy-linelength +// min-llvm-version 7.0 #![crate_type = "lib"] @@ -54,7 +55,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), +// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), *&E::A(0) } @@ -62,6 +63,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), +// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), *&E::A(0) } diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index 0693eae7d78..10dd12909b6 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength // compile-flags: -C no-prepopulate-passes +// min-llvm-version 7.0 #![crate_type = "lib"] #![feature(repr_packed)] @@ -63,7 +65,7 @@ pub struct BigPacked2 { pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. @@ -75,7 +77,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 2, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. @@ -93,14 +95,14 @@ pub struct Packed2Pair(u8, u32); // CHECK-LABEL: @pkd1_pair #[no_mangle] pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) { -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 5, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false) *pair2 = *pair1; } // CHECK-LABEL: @pkd2_pair #[no_mangle] pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) { -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 6, i32 2, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false) *pair2 = *pair1; } @@ -115,14 +117,14 @@ pub struct Packed2NestedPair((u32, u32)); // CHECK-LABEL: @pkd1_nested_pair #[no_mangle] pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) { -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false) *pair2 = *pair1; } // CHECK-LABEL: @pkd2_nested_pair #[no_mangle] pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) { -// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 2, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false) *pair2 = *pair1; } diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs index 8b3294281e9..8565335bd75 100644 --- a/src/test/codegen/repeat-trusted-len.rs +++ b/src/test/codegen/repeat-trusted-len.rs @@ -10,6 +10,7 @@ // compile-flags: -O // ignore-tidy-linelength +// min-llvm-version 7.0 #![crate_type = "lib"] @@ -23,6 +24,6 @@ pub fn helper(_: usize) { // CHECK-LABEL: @repeat_take_collect #[no_mangle] pub fn repeat_take_collect() -> Vec { -// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}%{{[0-9]+}}, i8 42, [[USIZE]] 100000, i32 1, i1 false) +// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}align 1 %{{[0-9]+}}, i8 42, [[USIZE]] 100000, i1 false) iter::repeat(42).take(100000).collect() } diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index d963c7e8ddf..16f86735c2e 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-emscripten -// min-llvm-version 6.0 +// min-llvm-version 7.0 // compile-flags: -C no-prepopulate-passes @@ -34,10 +34,9 @@ pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { simd_fmin(a, b) } -// FIXME(49261) -// // C_HECK-LABEL: @fmax -// #[no_mangle] -// pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { -// // C_HECK: call <4 x float> @llvm.maxnum.v4f32 -// simd_fmax(a, b) -// } +// CHECK-LABEL: @fmax +#[no_mangle] +pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.maxnum.v4f32 + simd_fmax(a, b) +} diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 08f5038fb18..0aaf00bfdbe 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -9,6 +9,8 @@ // except according to those terms. // compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength +// min-llvm-version 7.0 #![crate_type = "lib"] @@ -29,7 +31,7 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { // CHECK: store i32 %0, i32* [[TMP]] // CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false) *x = y; } @@ -43,6 +45,6 @@ pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { // CHECK: store i32 %0, i32* [[TMP]] // CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false) *x = y; } diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index e8c695f52be..6ec2978058d 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -2,7 +2,9 @@ all: ifeq ($(PROFILER_SUPPORT),1) +ifndef IS_WINDOWS $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) endif +endif diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 7dc227b5a14..96126ab7a79 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -2,7 +2,9 @@ all: ifeq ($(PROFILER_SUPPORT),1) +ifndef IS_WINDOWS $(RUSTC) -g -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) endif +endif diff --git a/src/test/run-pass/simd-intrinsic-float-math.rs b/src/test/run-pass/simd-intrinsic-float-math.rs index 4597674b3f1..3c7ca21459f 100644 --- a/src/test/run-pass/simd-intrinsic-float-math.rs +++ b/src/test/run-pass/simd-intrinsic-float-math.rs @@ -41,6 +41,24 @@ extern "platform-intrinsic" { fn simd_fpowi(x: T, y: i32) -> T; } +macro_rules! assert_approx_eq_f32 { + ($a:expr, $b:expr) => ({ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +} +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => ({ + let a = $a; + let b = $b; + assert_approx_eq_f32!(a.0, b.0); + assert_approx_eq_f32!(a.1, b.1); + assert_approx_eq_f32!(a.2, b.2); + assert_approx_eq_f32!(a.3, b.3); + }) +} + fn main() { let x = f32x4(1.0, 1.0, 1.0, 1.0); let y = f32x4(-1.0, -1.0, -1.0, -1.0); @@ -50,45 +68,45 @@ fn main() { unsafe { let r = simd_fabs(y); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_fcos(z); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_ceil(h); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_fexp(z); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_fexp2(z); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_floor(h); - assert_eq!(z, r); + assert_approx_eq!(z, r); let r = simd_fma(x, h, h); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_fsqrt(x); - assert_eq!(x, r); + assert_approx_eq!(x, r); let r = simd_flog(x); - assert_eq!(z, r); + assert_approx_eq!(z, r); let r = simd_flog2(x); - assert_eq!(z, r); + assert_approx_eq!(z, r); let r = simd_flog10(x); - assert_eq!(z, r); + assert_approx_eq!(z, r); let r = simd_fpow(h, x); - assert_eq!(h, r); + assert_approx_eq!(h, r); let r = simd_fpowi(h, 1); - assert_eq!(h, r); + assert_approx_eq!(h, r); let r = simd_fsin(z); - assert_eq!(z, r); + assert_approx_eq!(z, r); } } diff --git a/src/tools/lld b/src/tools/lld index b87873eaceb..8214ccf861d 160000 --- a/src/tools/lld +++ b/src/tools/lld @@ -1 +1 @@ -Subproject commit b87873eaceb75cf9342d5273f01ba2c020f61ca8 +Subproject commit 8214ccf861d538671b0a1436dbf4538dc4a64d09 -- cgit 1.4.1-3-g733a5 From 9c15a6606eff9c5821921f5cb6be305ccf8005de Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 3 Jul 2018 18:09:00 -0700 Subject: Ensure StorageDead is created even if variable initialization fails --- src/librustc_mir/build/expr/as_rvalue.rs | 4 +- src/librustc_mir/build/expr/as_temp.rs | 4 +- src/librustc_mir/build/matches/mod.rs | 18 +++- src/librustc_mir/build/mod.rs | 9 +- src/librustc_mir/build/scope.rs | 99 ++++++++++++++------- src/test/codegen/lifetime_start_end.rs | 6 +- src/test/mir-opt/issue-49232.rs | 148 +++++++++++++++++++++++++++++++ src/test/mir-opt/storage_ranges.rs | 2 +- 8 files changed, 246 insertions(+), 44 deletions(-) create mode 100644 src/test/mir-opt/issue-49232.rs (limited to 'src/test/codegen') diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d660b40e9cb..a1cea9259f6 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -102,7 +102,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); if let Some(scope) = scope { // schedule a shallow free of that memory, lest we unwind: - this.schedule_drop(expr_span, scope, &Place::Local(result), value.ty); + this.schedule_drop_storage_and_value( + expr_span, scope, &Place::Local(result), value.ty, + ); } // malloc some memory of suitable type (thus far, uninitialized): diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index d905b383316..f66fe763b75 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -62,7 +62,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // anything because no values with a destructor can be created in // a constant at this time, even if the type may need dropping. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, &Place::Local(temp), expr_ty); + this.schedule_drop_storage_and_value( + expr_span, temp_lifetime, &Place::Local(temp), expr_ty, + ); } block.and(temp) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 79dbdfefeb8..3a6c7dc9754 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -16,6 +16,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; +use build::scope::{CachedBlock, DropKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::ty::{self, Ty}; @@ -367,7 +368,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { source_info, kind: StatementKind::StorageLive(local_id) }); - Place::Local(local_id) + let place = Place::Local(local_id); + let var_ty = self.local_decls[local_id].ty; + let hir_id = self.hir.tcx().hir.node_to_hir_id(var); + let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); + self.schedule_drop( + span, region_scope, &place, var_ty, + DropKind::Storage, + ); + place } pub fn schedule_drop_for_binding(&mut self, @@ -378,7 +387,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let var_ty = self.local_decls[local_id].ty; let hir_id = self.hir.tcx().hir.node_to_hir_id(var); let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); - self.schedule_drop(span, region_scope, &Place::Local(local_id), var_ty); + self.schedule_drop( + span, region_scope, &Place::Local(local_id), var_ty, + DropKind::Value { + cached_block: CachedBlock::default(), + }, + ); } pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, f: &mut F) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4db5c8e9278..0a53511a4f9 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -10,6 +10,7 @@ use build; +use build::scope::{CachedBlock, DropKind}; use hair::cx::Cx; use hair::{LintLevel, BindingMode, PatternKind}; use rustc::hir; @@ -735,9 +736,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } // Make sure we drop (parts of) the argument even when not matched on. - self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), - argument_scope, &place, ty); - + self.schedule_drop( + pattern.as_ref().map_or(ast_body.span, |pat| pat.span), + argument_scope, &place, ty, + DropKind::Value { cached_block: CachedBlock::default() }, + ); } // Enter the argument pattern bindings source scope, if it exists. diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b9d6486d917..e99c6f4f987 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -144,12 +144,12 @@ struct DropData<'tcx> { /// place to drop location: Place<'tcx>, - /// Whether this is a full value Drop, or just a StorageDead. - kind: DropKind + /// Whether this is a value Drop or a StorageDead. + kind: DropKind, } #[derive(Debug, Default, Clone, Copy)] -struct CachedBlock { +pub(crate) struct CachedBlock { /// The cached block for the cleanups-on-diverge path. This block /// contains code to run the current drop and all the preceding /// drops (i.e. those having lower index in Drop’s Scope drop @@ -166,7 +166,7 @@ struct CachedBlock { } #[derive(Debug)] -enum DropKind { +pub(crate) enum DropKind { Value { cached_block: CachedBlock, }, @@ -622,25 +622,58 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { abortblk } + pub fn schedule_drop_storage_and_value( + &mut self, + span: Span, + region_scope: region::Scope, + place: &Place<'tcx>, + place_ty: Ty<'tcx>, + ) { + self.schedule_drop( + span, region_scope, place, place_ty, + DropKind::Storage, + ); + self.schedule_drop( + span, region_scope, place, place_ty, + DropKind::Value { + cached_block: CachedBlock::default(), + }, + ); + } + // Scheduling drops // ================ /// Indicates that `place` should be dropped on exit from /// `region_scope`. - pub fn schedule_drop(&mut self, - span: Span, - region_scope: region::Scope, - place: &Place<'tcx>, - place_ty: Ty<'tcx>) { + /// + /// When called with `DropKind::Storage`, `place` should be a local + /// with an index higher than the current `self.arg_count`. + pub fn schedule_drop( + &mut self, + span: Span, + region_scope: region::Scope, + place: &Place<'tcx>, + place_ty: Ty<'tcx>, + drop_kind: DropKind, + ) { let needs_drop = self.hir.needs_drop(place_ty); - let drop_kind = if needs_drop { - DropKind::Value { cached_block: CachedBlock::default() } - } else { - // Only temps and vars need their storage dead. - match *place { - Place::Local(index) if index.index() > self.arg_count => DropKind::Storage, - _ => return + match drop_kind { + DropKind::Value { .. } => if !needs_drop { return }, + DropKind::Storage => { + match *place { + Place::Local(index) => if index.index() <= self.arg_count { + span_bug!( + span, "`schedule_drop` called with index {} and arg_count {}", + index.index(), + self.arg_count, + ) + }, + _ => span_bug!( + span, "`schedule_drop` called with non-`Local` place {:?}", place + ), + } } - }; + } for scope in self.scopes.iter_mut().rev() { let this_scope = scope.region_scope == region_scope; @@ -895,24 +928,24 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, }); block = next; } - DropKind::Storage => {} - } - - // We do not need to emit StorageDead for generator drops - if generator_drop { - continue - } + DropKind::Storage => { + // We do not need to emit StorageDead for generator drops + if generator_drop { + continue + } - // Drop the storage for both value and storage drops. - // Only temps and vars need their storage dead. - match drop_data.location { - Place::Local(index) if index.index() > arg_count => { - cfg.push(block, Statement { - source_info, - kind: StatementKind::StorageDead(index) - }); + // Drop the storage for both value and storage drops. + // Only temps and vars need their storage dead. + match drop_data.location { + Place::Local(index) if index.index() > arg_count => { + cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageDead(index) + }); + } + _ => unreachable!(), + } } - _ => continue } } block.unit() diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index ea3f0de5d08..9f5170cc89e 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -31,11 +31,11 @@ pub fn test() { // CHECK: [[S__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* -// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) - // CHECK: [[E__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]]) + +// CHECK: [[E_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* +// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) } let c = 1; diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs new file mode 100644 index 00000000000..8e5a94abeed --- /dev/null +++ b/src/test/mir-opt/issue-49232.rs @@ -0,0 +1,148 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// We must mark a variable whose initialization fails due to an +// abort statement as StorageDead. + +fn main() { + loop { + let beacon = { + match true { + false => 4, + true => break, + } + }; + drop(&beacon); + } +} + +// END RUST SOURCE +// START rustc.main.mir_map.0.mir +// fn main() -> (){ +// let mut _0: (); +// scope 1 { +// } +// scope 2 { +// let _2: i32; +// } +// let mut _1: (); +// let mut _3: bool; +// let mut _4: u8; +// let mut _5: !; +// let mut _6: (); +// let mut _7: &i32; +// bb0: { +// goto -> bb1; +// } +// bb1: { +// falseUnwind -> [real: bb3, cleanup: bb4]; +// } +// bb2: { +// goto -> bb29; +// } +// bb3: { +// StorageLive(_2); +// StorageLive(_3); +// _3 = const true; +// _4 = discriminant(_3); +// switchInt(_3) -> [false: bb11, otherwise: bb10]; +// } +// bb4: { +// resume; +// } +// bb5: { +// _2 = const 4i32; +// goto -> bb14; +// } +// bb6: { +// _0 = (); +// goto -> bb15; +// } +// bb7: { +// falseEdges -> [real: bb12, imaginary: bb8]; +// } +// bb8: { +// falseEdges -> [real: bb13, imaginary: bb9]; +// } +// bb9: { +// unreachable; +// } +// bb10: { +// goto -> bb8; +// } +// bb11: { +// goto -> bb7; +// } +// bb12: { +// goto -> bb5; +// } +// bb13: { +// goto -> bb6; +// } +// bb14: { +// StorageDead(_3); +// StorageLive(_7); +// _7 = &_2; +// _6 = const std::mem::drop(move _7) -> [return: bb28, unwind: bb4]; +// } +// bb15: { +// goto -> bb16; +// } +// bb16: { +// goto -> bb17; +// } +// bb17: { +// goto -> bb18; +// } +// bb18: { +// goto -> bb19; +// } +// bb19: { +// goto -> bb20; +// } +// bb20: { +// StorageDead(_3); +// goto -> bb21; +// } +// bb21: { +// goto -> bb22; +// } +// bb22: { +// StorageDead(_2); +// goto -> bb23; +// } +// bb23: { +// goto -> bb24; +// } +// bb24: { +// goto -> bb25; +// } +// bb25: { +// goto -> bb2; +// } +// bb26: { +// _5 = (); +// unreachable; +// } +// bb27: { +// StorageDead(_5); +// goto -> bb14; +// } +// bb28: { +// StorageDead(_7); +// _1 = (); +// StorageDead(_2); +// goto -> bb1; +// } +// bb29: { +// return; +// } +// } +// END rustc.main.mir_map.0.mir diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 41eaf67d292..16e30f84d17 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -31,8 +31,8 @@ fn main() { // StorageDead(_5); // _3 = &_4; // _2 = (); -// StorageDead(_3); // StorageDead(_4); +// StorageDead(_3); // StorageLive(_6); // _6 = const 1i32; // _0 = (); -- cgit 1.4.1-3-g733a5 From 0d7e9933d3cac85bc1f11dc0fec67fcad77784ca Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 19 Jun 2018 04:08:20 +0800 Subject: Change RangeInclusive to a three-field struct. Fix #45222. --- src/libcore/iter/range.rs | 100 ++++++++++++---------------------------- src/libcore/ops/range.rs | 38 ++++++++++++--- src/libcore/slice/mod.rs | 20 ++++---- src/libcore/str/mod.rs | 20 ++++---- src/test/codegen/issue-45222.rs | 74 +++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 97 deletions(-) create mode 100644 src/test/codegen/issue-45222.rs (limited to 'src/test/codegen') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 0b279f66b88..16849e84f27 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -10,7 +10,7 @@ use convert::TryFrom; use mem; -use ops::{self, Add, Sub, Try}; +use ops::{self, Add, Sub}; use usize; use super::{FusedIterator, TrustedLen}; @@ -330,23 +330,23 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.start.add_one(); - Some(mem::replace(&mut self.start, n)) - } else { - let last = self.start.replace_one(); - self.end.replace_zero(); - Some(last) - } + if self.is_empty() { + self.is_iterating = Some(false); + return None; + } + if self.start < self.end { + let n = self.start.add_one(); + self.is_iterating = Some(true); + Some(mem::replace(&mut self.start, n)) } else { - None + self.is_iterating = Some(false); + Some(self.start.clone()) } } #[inline] fn size_hint(&self) -> (usize, Option) { - if !(self.start <= self.end) { + if self.is_empty() { return (0, Some(0)); } @@ -358,25 +358,29 @@ impl Iterator for ops::RangeInclusive { #[inline] fn nth(&mut self, n: usize) -> Option { + if self.is_empty() { + self.is_iterating = Some(false); + return None; + } + if let Some(plus_n) = self.start.add_usize(n) { use cmp::Ordering::*; match plus_n.partial_cmp(&self.end) { Some(Less) => { + self.is_iterating = Some(true); self.start = plus_n.add_one(); return Some(plus_n) } Some(Equal) => { - self.start.replace_one(); - self.end.replace_zero(); + self.is_iterating = Some(false); return Some(plus_n) } _ => {} } } - self.start.replace_one(); - self.end.replace_zero(); + self.is_iterating = Some(false); None } @@ -394,68 +398,24 @@ impl Iterator for ops::RangeInclusive { fn max(mut self) -> Option { self.next_back() } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.start.add_one(); - (mem::replace(&mut self.start, n), false) - } else { - self.end.replace_zero(); - (self.start.replace_one(), true) - }; - accum = f(accum, x)?; - if done { break } - } - } - Try::from_ok(accum) - } } #[stable(feature = "inclusive_range", since = "1.26.0")] impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.end.sub_one(); - Some(mem::replace(&mut self.end, n)) - } else { - let last = self.end.replace_zero(); - self.start.replace_one(); - Some(last) - } - } else { - None + if self.is_empty() { + self.is_iterating = Some(false); + return None; } - } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.end.sub_one(); - (mem::replace(&mut self.end, n), false) - } else { - self.start.replace_one(); - (self.end.replace_zero(), true) - }; - accum = f(accum, x)?; - if done { break } - } + if self.start < self.end { + let n = self.end.sub_one(); + self.is_iterating = Some(true); + Some(mem::replace(&mut self.end, n)) + } else { + self.is_iterating = Some(false); + Some(self.end.clone()) } - Try::from_ok(accum) } } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 01e279589da..3f9ac8a54bf 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -9,6 +9,7 @@ // except according to those terms. use fmt; +use hash::{Hash, Hasher}; /// An unbounded range (`..`). /// @@ -326,15 +327,37 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[doc(alias = "..=")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { - // FIXME: The current representation follows RFC 1980, - // but it is known that LLVM is not able to optimize loops following that RFC. - // Consider adding an extra `bool` field to indicate emptiness of the range. - // See #45222 for performance test cases. pub(crate) start: Idx, pub(crate) end: Idx, + pub(crate) is_iterating: Option, + // This field is: + // - `None` when next() or next_back() was never called + // - `Some(true)` when `start <= end` assuming no overflow + // - `Some(false)` otherwise + // The field cannot be a simple `bool` because the `..=` constructor can + // accept non-PartialOrd types, also we want the constructor to be const. +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl PartialEq for RangeInclusive { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.start == other.start && self.end == other.end + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Eq for RangeInclusive {} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Hash for RangeInclusive { + fn hash(&self, state: &mut H) { + self.start.hash(state); + self.end.hash(state); + } } impl RangeInclusive { @@ -350,7 +373,7 @@ impl RangeInclusive { #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end } + Self { start, end, is_iterating: None } } /// Returns the lower bound of the range (inclusive). @@ -492,8 +515,9 @@ impl> RangeInclusive { /// assert!(r.is_empty()); /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + #[inline] pub fn is_empty(&self) -> bool { - !(self.start <= self.end) + !self.is_iterating.unwrap_or_else(|| self.start <= self.end) } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ed29d80cb90..e6db4cb38ec 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2262,36 +2262,36 @@ impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get(slice) } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get_mut(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (self.start..self.end + 1).get_unchecked(slice) + (*self.start()..self.end() + 1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (self.start..self.end + 1).get_unchecked_mut(slice) + (*self.start()..self.end() + 1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &[T]) -> &[T] { - if self.end == usize::max_value() { slice_index_overflow_fail(); } - (self.start..self.end + 1).index(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.end == usize::max_value() { slice_index_overflow_fail(); } - (self.start..self.end + 1).index_mut(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index_mut(slice) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5ae2f6349e5..255e8a07d75 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2004,31 +2004,31 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::max_value() { None } - else { (self.start..self.end+1).get(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::max_value() { None } - else { (self.start..self.end+1).get_mut(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - (self.start..self.end+1).get_unchecked(slice) + (*self.start()..self.end()+1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - (self.start..self.end+1).get_unchecked_mut(slice) + (*self.start()..self.end()+1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::max_value() { str_index_overflow_fail(); } - (self.start..self.end+1).index(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::max_value() { str_index_overflow_fail(); } - (self.start..self.end+1).index_mut(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index_mut(slice) } } diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs new file mode 100644 index 00000000000..30a03243f01 --- /dev/null +++ b/src/test/codegen/issue-45222.rs @@ -0,0 +1,74 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O +// min-llvm-version 6.0 + +#![crate_type = "lib"] + +// verify that LLVM recognizes a loop involving 0..=n and will const-fold it. + +//------------------------------------------------------------------------------ +// Example from original issue #45222 + +fn foo2(n: u64) -> u64 { + let mut count = 0; + for _ in 0..n { + for j in (0..=n).rev() { + count += j; + } + } + count +} + +// CHECK-LABEL: @check_foo2 +#[no_mangle] +pub fn check_foo2() -> u64 { + // CHECK: ret i64 500005000000000 + foo2(100000) +} + +//------------------------------------------------------------------------------ +// Simplified example of #45222 + +fn triangle_inc(n: u64) -> u64 { + let mut count = 0; + for j in 0 ..= n { + count += j; + } + count +} + +// CHECK-LABEL: @check_triangle_inc +#[no_mangle] +pub fn check_triangle_inc() -> u64 { + // CHECK: ret i64 5000050000 + triangle_inc(100000) +} + +//------------------------------------------------------------------------------ +// Demo in #48012 + +fn foo3r(n: u64) -> u64 { + let mut count = 0; + (0..n).for_each(|_| { + (0 ..= n).rev().for_each(|j| { + count += j; + }) + }); + count +} + +// CHECK-LABEL: @check_foo3r +#[no_mangle] +pub fn check_foo3r() -> u64 { + // CHECK: ret i64 500005000000000 + foo3r(100000) +} -- cgit 1.4.1-3-g733a5 From e6fc62a1ef6cfb545d4f33914a4440c6bbcbf9eb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 4 Jul 2018 02:48:30 -0700 Subject: Don't use SIMD in mem::swap for types smaller than the block size LLVM isn't able to remove the alloca for the unaligned block in the SIMD tail in some cases, so doing this helps SRoA work in cases where it currently doesn't. Found in the `replace_with` RFC discussion. --- src/libcore/mem.rs | 2 +- src/libcore/ptr.rs | 13 +++++++++++++ src/test/codegen/swap-small-types.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/swap-small-types.rs (limited to 'src/test/codegen') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8fb4e0d6a02..a0fe6e98806 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -638,7 +638,7 @@ pub unsafe fn uninitialized() -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping(x, y, 1); + ptr::swap_nonoverlapping_one(x, y); } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0af642258c2..f1405b58e1b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -187,6 +187,19 @@ pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { swap_nonoverlapping_bytes(x, y, len) } +#[inline] +pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { + // For types smaller than the block optimization below, + // just swap directly to avoid pessimizing codegen. + if mem::size_of::() < 32 { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } else { + swap_nonoverlapping(x, y, 1); + } +} + #[inline] unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { // The approach here is to utilize simd to swap x & y efficiently. Testing reveals diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs new file mode 100644 index 00000000000..f34a1d669bd --- /dev/null +++ b/src/test/codegen/swap-small-types.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![crate_type = "lib"] + +use std::mem::swap; + +type RGB48 = [u16; 3]; + +// CHECK-LABEL: @swap_rgb48 +#[no_mangle] +pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { +// CHECK-NOT: alloca +// CHECK: load i48 +// CHECK: store i48 + swap(x, y) +} -- cgit 1.4.1-3-g733a5 From c9482f724f2c6369a56faddd3ba4c1f00545a086 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 21 Jul 2018 23:12:46 -0700 Subject: Only run the test on x86_64 Smaller platforms don't merge the loads the same way. --- src/test/codegen/swap-small-types.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs index f34a1d669bd..46406ee5182 100644 --- a/src/test/codegen/swap-small-types.rs +++ b/src/test/codegen/swap-small-types.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: -O +// only-x86_64 #![crate_type = "lib"] -- cgit 1.4.1-3-g733a5 From cc2bd71269f9c54fed3849141e29204a5f353693 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 Jul 2018 17:55:25 +0300 Subject: Add a test for sparc64 ABI issue --- src/test/codegen/sparc-struct-abi.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/codegen/sparc-struct-abi.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/sparc-struct-abi.rs b/src/test/codegen/sparc-struct-abi.rs new file mode 100644 index 00000000000..d3b7a5cd598 --- /dev/null +++ b/src/test/codegen/sparc-struct-abi.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Checks that we correctly codegen extern "C" functions returning structs. +// See issue #52638. + +// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: define i64 @structbool() +// CHECK-NEXT: start: +// CHECK-NEXT: ret i64 72057594037927936 +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} -- cgit 1.4.1-3-g733a5 From 90165b82fcd455deacfbecdc79953988342d5796 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Jul 2018 13:41:43 +0200 Subject: Make sure #47772 does not regress --- src/test/codegen/slice-position-bounds-check.rs | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/codegen/slice-position-bounds-check.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/slice-position-bounds-check.rs b/src/test/codegen/slice-position-bounds-check.rs new file mode 100644 index 00000000000..bcbf7fd83cf --- /dev/null +++ b/src/test/codegen/slice-position-bounds-check.rs @@ -0,0 +1,34 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-system-llvm +// compile-flags: -O +#![crate_type = "lib"] + +fn search(arr: &mut [T], a: &T) -> Result { + match arr.iter().position(|x| x == a) { + Some(p) => { + Ok(p) + }, + None => Err(()), + } +} + +// CHECK-LABEL: @position_no_bounds_check +#[no_mangle] +pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { + // This contains "call assume" so we cannot just rule out all calls + // CHECK-NOT: panic + if let Ok(p) = search(y, x) { + y[p] == *z + } else { + false + } +} -- cgit 1.4.1-3-g733a5 From 5ba76335bb76e8c31a24d77771885c57614ace9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Jul 2018 12:14:51 +0200 Subject: update codegen tests --- src/test/codegen/function-arguments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index c027dece014..5d5c7ced9f0 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -120,13 +120,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { pub fn str(_: &[u8]) { } -// CHECK: @trait_borrow({}* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1) +// CHECK: @trait_borrow({}* nonnull %arg0.0, [4 x [[USIZE]]]* noalias readonly dereferenceable({{32|16}}) %arg0.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) +// CHECK: @trait_box({}* noalias nonnull, [4 x [[USIZE]]]* noalias readonly dereferenceable({{32|16}})) #[no_mangle] pub fn trait_box(_: Box) { } -- cgit 1.4.1-3-g733a5 From 86e59ccf34214e33273af145df13a771607dc42e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Jul 2018 12:34:19 +0200 Subject: dont hardcode vtable size in codegen test --- src/test/codegen/function-arguments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 5d5c7ced9f0..09031508da1 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -120,13 +120,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { pub fn str(_: &[u8]) { } -// CHECK: @trait_borrow({}* nonnull %arg0.0, [4 x [[USIZE]]]* noalias readonly dereferenceable({{32|16}}) %arg0.1) +// CHECK: @trait_borrow({}* nonnull %arg0.0, [4 x [[USIZE]]]* noalias readonly dereferenceable({{.*}}) %arg0.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box({}* noalias nonnull, [4 x [[USIZE]]]* noalias readonly dereferenceable({{32|16}})) +// CHECK: @trait_box({}* noalias nonnull, [4 x [[USIZE]]]* noalias readonly dereferenceable({{.*}})) #[no_mangle] pub fn trait_box(_: Box) { } -- cgit 1.4.1-3-g733a5 From 50773991d3f8dee3cda032f6d1289277cdd9da25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Jul 2018 22:29:49 +0200 Subject: make sure that the no-panic test tests what it is supposed to test --- src/test/codegen/slice-position-bounds-check.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/slice-position-bounds-check.rs b/src/test/codegen/slice-position-bounds-check.rs index bcbf7fd83cf..aae81ae8492 100644 --- a/src/test/codegen/slice-position-bounds-check.rs +++ b/src/test/codegen/slice-position-bounds-check.rs @@ -32,3 +32,11 @@ pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { false } } + +// just to make sure that panicking really emits "panic" somewhere in the IR +// CHECK-LABEL: @test_check +#[no_mangle] +pub fn test_check() { + // CHECK: panic + unreachable!() +} -- cgit 1.4.1-3-g733a5 From fb7d8a12db2a561c7dcc2534714243793446c7c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Jul 2018 10:35:27 +0200 Subject: hopefully make test pass on windows --- src/test/codegen/slice-position-bounds-check.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/slice-position-bounds-check.rs b/src/test/codegen/slice-position-bounds-check.rs index aae81ae8492..a6c846d7dab 100644 --- a/src/test/codegen/slice-position-bounds-check.rs +++ b/src/test/codegen/slice-position-bounds-check.rs @@ -9,7 +9,7 @@ // except according to those terms. // no-system-llvm -// compile-flags: -O +// compile-flags: -O -C panic=abort #![crate_type = "lib"] fn search(arr: &mut [T], a: &T) -> Result { @@ -25,7 +25,7 @@ fn search(arr: &mut [T], a: &T) -> Result { #[no_mangle] pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { // This contains "call assume" so we cannot just rule out all calls - // CHECK-NOT: panic + // CHECK-NOT: panic_bounds_check if let Ok(p) = search(y, x) { y[p] == *z } else { @@ -33,10 +33,10 @@ pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { } } -// just to make sure that panicking really emits "panic" somewhere in the IR +// just to make sure that panicking really emits "panic_bounds_check" somewhere in the IR // CHECK-LABEL: @test_check #[no_mangle] -pub fn test_check() { - // CHECK: panic - unreachable!() +pub fn test_check(y: &[i32]) -> i32 { + // CHECK: panic_bounds_check + y[12] } -- cgit 1.4.1-3-g733a5 From 38e311e4486b475c498ed1afdb6a036cdd702ebf Mon Sep 17 00:00:00 2001 From: Laurentiu Nicola Date: Tue, 31 Jul 2018 18:36:04 +0300 Subject: Use SetLenOnDrop in Vec::truncate() This avoids a redundant length check in some cases when calling `Vec::truncate` or `Vec::clear`. Fixes #51802 --- src/liballoc/vec.rs | 23 +++++++++++++++++------ src/test/codegen/vec-clear.rs | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/test/codegen/vec-clear.rs (limited to 'src/test/codegen') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 5efe1e23309..cc913dfbb4b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -690,14 +690,20 @@ impl Vec { /// [`drain`]: #method.drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { + let current_len = self.len; unsafe { + let mut ptr = self.as_mut_ptr().offset(self.len as isize); + // Set the final length at the end, keeping in mind that + // dropping an element might panic. Works around a missed + // optimization, as seen in the following issue: + // https://github.com/rust-lang/rust/issues/51802 + let mut local_len = SetLenOnDrop::new(&mut self.len); + // drop any extra elements - while len < self.len { - // decrement len before the drop_in_place(), so a panic on Drop - // doesn't re-drop the just-failed value. - self.len -= 1; - let len = self.len; - ptr::drop_in_place(self.get_unchecked_mut(len)); + for _ in len..current_len { + local_len.decrement_len(1); + ptr = ptr.offset(-1); + ptr::drop_in_place(ptr); } } } @@ -1512,6 +1518,11 @@ impl<'a> SetLenOnDrop<'a> { fn increment_len(&mut self, increment: usize) { self.local_len += increment; } + + #[inline] + fn decrement_len(&mut self, decrement: usize) { + self.local_len -= decrement; + } } impl<'a> Drop for SetLenOnDrop<'a> { diff --git a/src/test/codegen/vec-clear.rs b/src/test/codegen/vec-clear.rs new file mode 100644 index 00000000000..a73dd077cea --- /dev/null +++ b/src/test/codegen/vec-clear.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @vec_clear +#[no_mangle] +pub fn vec_clear(x: &mut Vec) { + // CHECK-NOT: load + // CHECK-NOT: icmp + x.clear() +} -- cgit 1.4.1-3-g733a5 From 40a60464d4172db38f72a6f4f1141aa117f7d672 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 31 Jul 2018 22:37:41 +0300 Subject: Only run the sparc-abi test on sparc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not required for LLVM to have SPARC target support, so it is necessary to only run this test when LLVM does support SPARC. Sadly, it isn’t possible to specify exactly this constraint. Instead, we specify that this test should run on SPARC host only (it surely is sane assumption to make that compiler running on a SPARC can generate SPARC, right?) Since you cannot specify multiple `only-*` to have it run on both 32-bit and 64-bit SPARC we pick 64-bit SPARC, because it is exactly what is being tested by this test. Fixes #52881 --- src/test/codegen/sparc-struct-abi.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test/codegen') diff --git a/src/test/codegen/sparc-struct-abi.rs b/src/test/codegen/sparc-struct-abi.rs index d3b7a5cd598..56c4364d598 100644 --- a/src/test/codegen/sparc-struct-abi.rs +++ b/src/test/codegen/sparc-struct-abi.rs @@ -11,6 +11,7 @@ // Checks that we correctly codegen extern "C" functions returning structs. // See issue #52638. +// only-sparc64 // compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib #![feature(no_core, lang_items)] #![no_core] -- cgit 1.4.1-3-g733a5 From 02190f397ecb32bca42e5b631dc235381d01b377 Mon Sep 17 00:00:00 2001 From: Colin Pronovost Date: Wed, 23 May 2018 15:19:07 -0400 Subject: Make globals with private linkage unnamed. Fixes #50862. --- src/librustc_codegen_llvm/consts.rs | 20 +++++++++++++------- src/librustc_codegen_llvm/declare.rs | 10 +++++++++- src/librustc_codegen_llvm/llvm/ffi.rs | 1 + src/librustc_codegen_llvm/meth.rs | 2 +- src/librustc_codegen_llvm/mir/block.rs | 4 ++-- src/librustc_codegen_llvm/mir/constant.rs | 4 ++-- src/librustc_codegen_llvm/mir/place.rs | 2 +- src/rustllvm/RustWrapper.cpp | 10 ++++++++++ src/test/codegen/consts.rs | 4 ++-- src/test/codegen/remap_path_prefix/main.rs | 2 +- .../symbols-are-reasonable/Makefile | 13 ------------- .../run-make-fulldeps/symbols-are-reasonable/lib.rs | 21 --------------------- 12 files changed, 42 insertions(+), 51 deletions(-) delete mode 100644 src/test/run-make-fulldeps/symbols-are-reasonable/Makefile delete mode 100644 src/test/run-make-fulldeps/symbols-are-reasonable/lib.rs (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 72ff65361ca..21bf490beb0 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -66,16 +66,22 @@ pub fn addr_of_mut( cx: &CodegenCx<'ll, '_>, cv: &'ll Value, align: Align, - kind: &str, + kind: Option<&str>, ) -> &'ll Value { unsafe { - let name = cx.generate_local_symbol_name(kind); - let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{ - bug!("symbol `{}` is already defined", name); - }); + let gv = match kind { + Some(kind) if !cx.tcx.sess.fewer_names() => { + let name = cx.generate_local_symbol_name(kind); + let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", name); + }); + llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); + gv + }, + _ => declare::define_private_global(cx, val_ty(cv)), + }; llvm::LLVMSetInitializer(gv, cv); set_global_alignment(cx, gv, align); - llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); SetUnnamedAddr(gv, true); gv } @@ -85,7 +91,7 @@ pub fn addr_of( cx: &CodegenCx<'ll, '_>, cv: &'ll Value, align: Align, - kind: &str, + kind: Option<&str>, ) -> &'ll Value { if let Some(&gv) = cx.const_globals.borrow().get(&cv) { unsafe { diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 9812d7f9a41..a0310eecd59 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -35,7 +35,6 @@ use value::Value; use std::ffi::CString; - /// Declare a global value. /// /// If there’s a value with the same name already declared, the function will @@ -170,6 +169,15 @@ pub fn define_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> Opti } } +/// Declare a private global +/// +/// Use this function when you intend to define a global without a name. +pub fn define_private_global(cx: &CodegenCx<'ll, '_>, ty: &'ll Type) -> &'ll Value { + unsafe { + llvm::LLVMRustInsertPrivateGlobal(cx.llmod, ty) + } +} + /// Declare a Rust function with an intention to define it. /// /// Use this function when you intend to define a function. This function will diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 898d3d67353..71304453134 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -622,6 +622,7 @@ extern "C" { pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value; + pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value; pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub fn LLVMDeleteGlobal(GlobalVar: &Value); diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs index 9c0dd0dc3d8..8a1159bc477 100644 --- a/src/librustc_codegen_llvm/meth.rs +++ b/src/librustc_codegen_llvm/meth.rs @@ -106,7 +106,7 @@ pub fn get_vtable( let vtable_const = C_struct(cx, &components, false); let align = cx.data_layout().pointer_align; - let vtable = consts::addr_of(cx, vtable_const, align, "vtable"); + let vtable = consts::addr_of(cx, vtable_const, align, Some("vtable")); debuginfo::create_vtable_metadata(cx, ty, vtable); diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index 684ecfaeec8..4e389c3b915 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -377,7 +377,7 @@ impl FunctionCx<'a, 'll, 'tcx> { let file_line_col = consts::addr_of(bx.cx, file_line_col, align, - "panic_bounds_check_loc"); + Some("panic_bounds_check_loc")); (lang_items::PanicBoundsCheckFnLangItem, vec![file_line_col, index, len]) } @@ -391,7 +391,7 @@ impl FunctionCx<'a, 'll, 'tcx> { let msg_file_line_col = consts::addr_of(bx.cx, msg_file_line_col, align, - "panic_loc"); + Some("panic_loc")); (lang_items::PanicFnLangItem, vec![msg_file_line_col]) } diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index 341ed9df64b..e414af07c9c 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -56,9 +56,9 @@ pub fn scalar_to_llvm( Some(AllocType::Memory(alloc)) => { let init = const_alloc_to_llvm(cx, alloc); if alloc.runtime_mutability == Mutability::Mutable { - consts::addr_of_mut(cx, init, alloc.align, "byte_str") + consts::addr_of_mut(cx, init, alloc.align, None) } else { - consts::addr_of(cx, init, alloc.align, "byte_str") + consts::addr_of(cx, init, alloc.align, None) } } Some(AllocType::Function(fn_instance)) => { diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index abc3dbdab2f..6fa0845dd0c 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -63,7 +63,7 @@ impl PlaceRef<'ll, 'tcx> { offset: Size, ) -> PlaceRef<'ll, 'tcx> { let init = const_alloc_to_llvm(bx.cx, alloc); - let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + let base_addr = consts::addr_of(bx.cx, init, layout.align, None); let llval = unsafe { LLVMConstInBoundsGEP( consts::bitcast(base_addr, Type::i8p(bx.cx)), diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index f2b5297285c..ce865dfbec2 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -12,6 +12,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" @@ -116,6 +117,15 @@ LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty) { return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); } +extern "C" LLVMValueRef +LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty) { + return wrap(new GlobalVariable(*unwrap(M), + unwrap(Ty), + false, + GlobalValue::PrivateLinkage, + nullptr)); +} + extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 30fffbb769b..301f5544486 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -21,11 +21,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @{{[0-9]+}} = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 4fb8c37558d..dd0f89c931d 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -22,7 +22,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @byte_str.1 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 +// CHECK: @0 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/src/test/run-make-fulldeps/symbols-are-reasonable/Makefile b/src/test/run-make-fulldeps/symbols-are-reasonable/Makefile deleted file mode 100644 index a6d294d2a1c..00000000000 --- a/src/test/run-make-fulldeps/symbols-are-reasonable/Makefile +++ /dev/null @@ -1,13 +0,0 @@ --include ../tools.mk - -# check that the compile generated symbols for strings, binaries, -# vtables, etc. have semisane names (e.g. `str.1234`); it's relatively -# easy to accidentally modify the compiler internals to make them -# become things like `str"str"(1234)`. - -OUT=$(TMPDIR)/lib.s - -all: - $(RUSTC) lib.rs --emit=asm --crate-type=staticlib - # just check for symbol declarations with the names we're expecting. - $(CGREP) -e 'str\.[0-9]+:' 'byte_str\.[0-9]+:' 'vtable\.[0-9]+' < $(OUT) diff --git a/src/test/run-make-fulldeps/symbols-are-reasonable/lib.rs b/src/test/run-make-fulldeps/symbols-are-reasonable/lib.rs deleted file mode 100644 index b9285b24cd6..00000000000 --- a/src/test/run-make-fulldeps/symbols-are-reasonable/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub static X: &'static str = "foobarbaz"; -pub static Y: &'static [u8] = include_bytes!("lib.rs"); - -trait Foo { fn dummy(&self) { } } -impl Foo for usize {} - -#[no_mangle] -pub extern "C" fn dummy() { - // force the vtable to be created - let _x = &1usize as &Foo; -} -- cgit 1.4.1-3-g733a5 From 1001b2beee595db76ae9d612134271e4a971fed8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Aug 2018 18:45:15 +0200 Subject: inore some codegen tests when debug assertions are enabled --- .travis.yml | 2 ++ src/test/codegen/vec-clear.rs | 1 + src/test/codegen/vec-iter-collect-len.rs | 1 + src/test/codegen/vec-optimizes-away.rs | 1 + src/tools/compiletest/src/header.rs | 6 ++++-- 5 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/.travis.yml b/.travis.yml index 0228fdc994d..16e55ca2348 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,8 @@ matrix: # slow to run. # OSX builders running tests, these run the full test suite. + # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some + # runners that run `//ignore-debug` tests. # # Note that the compiler is compiled to target 10.8 here because the Xcode # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. diff --git a/src/test/codegen/vec-clear.rs b/src/test/codegen/vec-clear.rs index a73dd077cea..c44637376d7 100644 --- a/src/test/codegen/vec-clear.rs +++ b/src/test/codegen/vec-clear.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-debug: the debug assertions get in the way // compile-flags: -O #![crate_type = "lib"] diff --git a/src/test/codegen/vec-iter-collect-len.rs b/src/test/codegen/vec-iter-collect-len.rs index efb384d0afb..05cbf053444 100644 --- a/src/test/codegen/vec-iter-collect-len.rs +++ b/src/test/codegen/vec-iter-collect-len.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-debug: the debug assertions get in the way // no-system-llvm // compile-flags: -O #![crate_type="lib"] diff --git a/src/test/codegen/vec-optimizes-away.rs b/src/test/codegen/vec-optimizes-away.rs index 261564ed51a..6bef01fd4ea 100644 --- a/src/test/codegen/vec-optimizes-away.rs +++ b/src/test/codegen/vec-optimizes-away.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // +// ignore-debug: the debug assertions get in the way // no-system-llvm // compile-flags: -O #![crate_type="lib"] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5f68d00eab1..3fd67366a8c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -615,12 +615,14 @@ impl Config { common::DebugInfoLldb => name == "lldb", common::Pretty => name == "pretty", _ => false, - } || (self.target != self.host && name == "cross-compile") || + } || + (self.target != self.host && name == "cross-compile") || match self.compare_mode { Some(CompareMode::Nll) => name == "compare-mode-nll", Some(CompareMode::Polonius) => name == "compare-mode-polonius", None => false, - } + } || + (cfg!(debug_assertions) && name == "debug") } else { false } -- cgit 1.4.1-3-g733a5 From 386e000c5f28dfac697ae145524bcc1c17759993 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 3 Aug 2018 17:07:38 +0200 Subject: Add test case for omitting dllimport during cross-lang LTO. --- src/test/codegen/no-dllimport-w-cross-lang-lto.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/codegen/no-dllimport-w-cross-lang-lto.rs (limited to 'src/test/codegen') diff --git a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs new file mode 100644 index 00000000000..025e7cbf179 --- /dev/null +++ b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +// no-prefer-dynamic +// only-msvc +// compile-flags: -C no-prepopulate-passes -Z cross-lang-lto + +#![crate_type = "rlib"] + +// CHECK-NOT: @{{.*}}__imp_{{.*}}GLOBAL{{.*}} = global i8* + +pub static GLOBAL: u32 = 0; +pub static mut GLOBAL2: u32 = 0; -- cgit 1.4.1-3-g733a5 From b27a161939620626ca5fdcb9f4dd486a6ed1e827 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 2 Aug 2018 18:10:26 +0200 Subject: Annotate functions in LLVM with target-cpu, same as Clang does. --- src/librustc_codegen_llvm/attributes.rs | 18 ++++++++++++++++++ src/librustc_codegen_llvm/base.rs | 1 + src/librustc_codegen_llvm/context.rs | 3 +++ src/test/codegen/target-cpu-on-functions.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 src/test/codegen/target-cpu-on-functions.rs (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index c52f8944108..714e8914e48 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -123,6 +123,15 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator { .filter(|l| !l.is_empty()) } +pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + let target_cpu = CString::new(cx.tcx.sess.target_cpu().to_string()).unwrap(); + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + cstr("target-cpu\0"), + target_cpu.as_c_str()); +} + /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { @@ -167,6 +176,15 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { Some(true) | None => {} } + // Always annotate functions with the target-cpu they are compiled for. + // Without this, ThinLTO won't inline Rust functions into Clang generated + // functions (because Clang annotates functions this way too). + // NOTE: For now we just apply this if -Zcross-lang-lto is specified, since + // it introduce a little overhead and isn't really necessary otherwise. + if cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() { + apply_target_cpu_attr(cx, llfn); + } + let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) .chain( diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 41336165684..13e8426155a 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -596,6 +596,7 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { // `main` should respect same config for frame pointer elimination as rest of code attributes::set_frame_pointer_elimination(cx, llfn); + attributes::apply_target_cpu_attr(cx, llfn); let bx = Builder::new_block(cx, llfn, "top"); diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 2f557d0b099..7a308bb6e88 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use attributes; use common; use llvm; use rustc::dep_graph::DepGraphSafe; @@ -381,6 +382,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { declare::declare_cfn(self, name, fty) } }; + attributes::apply_target_cpu_attr(self, llfn); self.eh_personality.set(Some(llfn)); llfn } @@ -412,6 +414,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty); attributes::unwind(llfn, true); + attributes::apply_target_cpu_attr(self, llfn); unwresume.set(Some(llfn)); llfn } diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs new file mode 100644 index 00000000000..c2765a46caa --- /dev/null +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +// only-x86_64 +// compile-flags: -C no-prepopulate-passes -C panic=abort + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern fn exported() { + not_exported(); +} + +// CHECK-LABEL: define {{.*}} @_ZN23target_cpu_on_functions12not_exported{{.*}}() {{.*}} #0 +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "target-cpu"="x86-64" -- cgit 1.4.1-3-g733a5 From 3a7005037726263c0beffd0efc3d5d147b2a86b4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 6 Aug 2018 11:16:28 +0200 Subject: Address review comments for #53031 and fix some merge fallout. --- src/librustc/session/mod.rs | 7 +++++++ src/librustc_codegen_llvm/back/link.rs | 10 +++++----- src/librustc_codegen_llvm/back/write.rs | 2 +- src/test/codegen/no-dllimport-w-cross-lang-lto.rs | 2 +- src/test/codegen/target-cpu-on-functions.rs | 4 +++- .../run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile | 4 ++-- 6 files changed, 19 insertions(+), 10 deletions(-) (limited to 'src/test/codegen') diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 505511a4a0c..9a3ce50fcbd 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1202,6 +1202,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.err("can't perform LTO when compiling incrementally"); } + // Since we don't know if code in an rlib will be linked to statically or + // dynamically downstream, rustc generates `__imp_` symbols that help the + // MSVC linker deal with this lack of knowledge (#27438). Unfortunately, + // these manually generated symbols confuse LLD when it tries to merge + // bitcode during ThinLTO. Therefore we disallow dynamic linking on MSVC + // when compiling for LLD ThinLTO. This way we can validly just not generate + // the `dllimport` attributes and `__imp_` symbols in that case. if sess.opts.debugging_opts.cross_lang_lto.enabled() && sess.opts.cg.prefer_dynamic && sess.target.target.options.is_like_msvc { diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 72084c170aa..50d41d76986 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -563,7 +563,7 @@ fn link_staticlib(sess: &Session, }); ab.add_rlib(path, &name.as_str(), - is_full_lto_enabled(sess) && + are_upstream_rust_objects_already_included(sess) && !ignored_for_lto(sess, &codegen_results.crate_info, cnum), skip_object_files).unwrap(); @@ -1446,7 +1446,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - if (!is_full_lto_enabled(sess) || + if (!are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && crate_type != config::CrateType::Dylib && !skip_native { @@ -1500,7 +1500,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - let skip_because_lto = is_full_lto_enabled(sess) && + let skip_because_lto = are_upstream_rust_objects_already_included(sess) && is_rust_object && (sess.target.target.options.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum)); @@ -1537,7 +1537,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { // If we're performing LTO, then it should have been previously required // that all upstream rust dependencies were available in an rlib format. - assert!(!is_full_lto_enabled(sess)); + assert!(!are_upstream_rust_objects_already_included(sess)); // Just need to tell the linker about where the library lives and // what its name is @@ -1623,7 +1623,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { } } -fn is_full_lto_enabled(sess: &Session) -> bool { +fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { match sess.lto() { Lto::Yes | Lto::Fat => true, diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 47440d864d5..640e1c1f3d4 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -2385,7 +2385,7 @@ fn msvc_imps_needed(tcx: TyCtxt) -> bool { tcx.sess.opts.cg.prefer_dynamic)); tcx.sess.target.target.options.is_like_msvc && - tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) && + tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing // dynamic linking when cross-language LTO is enabled. diff --git a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs index 025e7cbf179..0d5d02206a6 100644 --- a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs +++ b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs @@ -13,7 +13,7 @@ // no-prefer-dynamic // only-msvc -// compile-flags: -C no-prepopulate-passes -Z cross-lang-lto +// compile-flags: -Z cross-lang-lto #![crate_type = "rlib"] diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs index c2765a46caa..1a6ab22e568 100644 --- a/src/test/codegen/target-cpu-on-functions.rs +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -11,8 +11,10 @@ // This test makes sure that functions get annotated with the proper // "target-cpu" attribute in LLVM. +// no-prefer-dynamic +// ignore-tidy-linelength // only-x86_64 -// compile-flags: -C no-prepopulate-passes -C panic=abort +// compile-flags: -C no-prepopulate-passes -C panic=abort -Z cross-lang-lto -Cpasses=name-anon-globals #![crate_type = "staticlib"] diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile index de42c6e0eb5..0a6f226a027 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile @@ -11,7 +11,7 @@ all: staticlib.rs upstream.rs $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -L. -o $(TMPDIR)/staticlib.a (cd $(TMPDIR); llvm-ar x ./staticlib.a) # Make sure the upstream object file was included - ls upstream.*.rcgu.o + ls $(TMPDIR)/upstream.*.rcgu.o # Cleanup rm $(TMPDIR)/* @@ -20,4 +20,4 @@ all: staticlib.rs upstream.rs $(RUSTC) upstream.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin -L. -o $(TMPDIR)/staticlib.a (cd $(TMPDIR); llvm-ar x ./staticlib.a) - ls upstream.*.rcgu.o + ls $(TMPDIR)/upstream.*.rcgu.o -- cgit 1.4.1-3-g733a5 From 49972e93ffdd6d70ddfef8486d1642cec69bfaeb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 9 Aug 2018 09:39:02 +0200 Subject: Relax the target-cpu-on-function codegen test so it just checks for presence of the attribute. --- src/test/codegen/target-cpu-on-functions.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/test/codegen') diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs index 1a6ab22e568..cd7d061c0de 100644 --- a/src/test/codegen/target-cpu-on-functions.rs +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -13,7 +13,6 @@ // no-prefer-dynamic // ignore-tidy-linelength -// only-x86_64 // compile-flags: -C no-prepopulate-passes -C panic=abort -Z cross-lang-lto -Cpasses=name-anon-globals #![crate_type = "staticlib"] @@ -27,4 +26,4 @@ pub extern fn exported() { // CHECK-LABEL: define {{.*}} @_ZN23target_cpu_on_functions12not_exported{{.*}}() {{.*}} #0 fn not_exported() {} -// CHECK: attributes #0 = {{.*}} "target-cpu"="x86-64" +// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}" -- cgit 1.4.1-3-g733a5 From dc02a6070f899b87249efa8c09bb2b90dbe94b0d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 12 Aug 2018 15:27:03 +0300 Subject: Do not generate assumes for plain integer casts --- src/librustc_codegen_llvm/mir/rvalue.rs | 4 +++- src/librustc_target/abi/mod.rs | 11 ++++++++++- src/test/codegen/no-assumes-on-casts.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/test/codegen/no-assumes-on-casts.rs (limited to 'src/test/codegen') diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index dda33ae3fec..7eac8e735ed 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -304,7 +304,9 @@ impl FunctionCx<'a, 'll, 'tcx> { // then `i1 1` (i.e. E::B) is effectively `i8 -1`. signed = !scalar.is_bool() && s; - if scalar.valid_range.end() > scalar.valid_range.start() { + let er = scalar.valid_range_exclusive(bx.cx); + if er.end != er.start && + scalar.valid_range.end() > scalar.valid_range.start() { // We want `table[e as usize]` to not // have bound checks, and this is the most // convenient place to put the `assume`. diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 4f25360d8ea..16b5241b29a 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -596,7 +596,16 @@ pub struct Scalar { pub value: Primitive, /// Inclusive wrap-around range of valid values, that is, if - /// min > max, it represents min..=u128::MAX followed by 0..=max. + /// start > end, it represents `start..=max_value()`, + /// followed by `0..=end`. + /// + /// That is, for an i8 primitive, a range of `254..=2` means following + /// sequence: + /// + /// 254 (-2), 255 (-1), 0, 1, 2 + /// + /// This is intended specifically to mirror LLVM’s `!range` metadata, + /// semantics. // FIXME(eddyb) always use the shortest range, e.g. by finding // the largest space between two consecutive valid values and // taking everything else as the (shortest) valid range. diff --git a/src/test/codegen/no-assumes-on-casts.rs b/src/test/codegen/no-assumes-on-casts.rs new file mode 100644 index 00000000000..a5a7d94a553 --- /dev/null +++ b/src/test/codegen/no-assumes-on-casts.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +// compile-flags: -Cno-prepopulate-passes + +// CHECK-LABEL: fna +#[no_mangle] +pub fn fna(a: i16) -> i32 { + a as i32 +// CHECK-NOT: assume +// CHECK: sext +} + +// CHECK-LABEL: fnb +#[no_mangle] +pub fn fnb(a: u16) -> u32 { + a as u32 +// CHECK-NOT: assume +// CHECK: zext +} -- cgit 1.4.1-3-g733a5