Skip to content

Commit

Permalink
Auto merge of #62555 - Centril:rollup-ti46adx, r=Centril
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #61853 (Emit warning when trying to use PGO in conjunction with unwinding on …)
 - #62278 (Add Iterator::partition_in_place() and is_partitioned())
 - #62283 (Target::arch can take more than listed options)
 - #62393 (Fix pretty-printing of `$crate` (take 4))
 - #62474 (Prepare for LLVM 9 update)

Failed merges:

r? @ghost
  • Loading branch information
bors committed Jul 10, 2019
2 parents 3f435f6 + 6c0a406 commit 0324a2b
Show file tree
Hide file tree
Showing 60 changed files with 551 additions and 180 deletions.
100 changes: 100 additions & 0 deletions src/libcore/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,11 @@ pub trait Iterator {
/// `partition()` returns a pair, all of the elements for which it returned
/// `true`, and all of the elements for which it returned `false`.
///
/// See also [`is_partitioned()`] and [`partition_in_place()`].
///
/// [`is_partitioned()`]: #method.is_partitioned
/// [`partition_in_place()`]: #method.partition_in_place
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1506,6 +1511,101 @@ pub trait Iterator {
(left, right)
}

/// Reorder the elements of this iterator *in-place* according to the given predicate,
/// such that all those that return `true` precede all those that return `false`.
/// Returns the number of `true` elements found.
///
/// The relative order of partitioned items is not maintained.
///
/// See also [`is_partitioned()`] and [`partition()`].
///
/// [`is_partitioned()`]: #method.is_partitioned
/// [`partition()`]: #method.partition
///
/// # Examples
///
/// ```
/// #![feature(iter_partition_in_place)]
///
/// let mut a = [1, 2, 3, 4, 5, 6, 7];
///
/// // Partition in-place between evens and odds
/// let i = a.iter_mut().partition_in_place(|&n| n % 2 == 0);
///
/// assert_eq!(i, 3);
/// assert!(a[..i].iter().all(|&n| n % 2 == 0)); // evens
/// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds
/// ```
#[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")]
fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize
where
Self: Sized + DoubleEndedIterator<Item = &'a mut T>,
P: FnMut(&T) -> bool,
{
// FIXME: should we worry about the count overflowing? The only way to have more than
// `usize::MAX` mutable references is with ZSTs, which aren't useful to partition...

// These closure "factory" functions exist to avoid genericity in `Self`.

#[inline]
fn is_false<'a, T>(
predicate: &'a mut impl FnMut(&T) -> bool,
true_count: &'a mut usize,
) -> impl FnMut(&&mut T) -> bool + 'a {
move |x| {
let p = predicate(&**x);
*true_count += p as usize;
!p
}
}

#[inline]
fn is_true<T>(
predicate: &mut impl FnMut(&T) -> bool
) -> impl FnMut(&&mut T) -> bool + '_ {
move |x| predicate(&**x)
}

// Repeatedly find the first `false` and swap it with the last `true`.
let mut true_count = 0;
while let Some(head) = self.find(is_false(predicate, &mut true_count)) {
if let Some(tail) = self.rfind(is_true(predicate)) {
crate::mem::swap(head, tail);
true_count += 1;
} else {
break;
}
}
true_count
}

/// Checks if the elements of this iterator are partitioned according to the given predicate,
/// such that all those that return `true` precede all those that return `false`.
///
/// See also [`partition()`] and [`partition_in_place()`].
///
/// [`partition()`]: #method.partition
/// [`partition_in_place()`]: #method.partition_in_place
///
/// # Examples
///
/// ```
/// #![feature(iter_is_partitioned)]
///
/// assert!("Iterator".chars().is_partitioned(char::is_uppercase));
/// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase));
/// ```
#[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")]
fn is_partitioned<P>(mut self, mut predicate: P) -> bool
where
Self: Sized,
P: FnMut(Self::Item) -> bool,
{
// Either all items test `true`, or the first clause stops at `false`
// and we check that there are no more `true` items after that.
self.all(&mut predicate) || !self.any(predicate)
}

/// An iterator method that applies a function as long as it returns
/// successfully, producing a single, final value.
///
Expand Down
36 changes: 36 additions & 0 deletions src/libcore/tests/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2460,3 +2460,39 @@ fn test_is_sorted() {
assert!(!["c", "bb", "aaa"].iter().is_sorted());
assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
}

#[test]
fn test_partition() {
fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) {
let i = xs.iter_mut().partition_in_place(p);
assert_eq!(expected, i);
assert!(xs[..i].iter().all(p));
assert!(!xs[i..].iter().any(p));
assert!(xs.iter().is_partitioned(p));
if i == 0 || i == xs.len() {
assert!(xs.iter().rev().is_partitioned(p));
} else {
assert!(!xs.iter().rev().is_partitioned(p));
}
}

check(&mut [], |_| true, 0);
check(&mut [], |_| false, 0);

check(&mut [0], |_| true, 1);
check(&mut [0], |_| false, 0);

check(&mut [-1, 1], |&x| x > 0, 1);
check(&mut [-1, 1], |&x| x < 0, 1);

let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
check(xs, |_| true, 10);
check(xs, |_| false, 0);
check(xs, |&x| x % 2 == 0, 5); // evens
check(xs, |&x| x % 2 == 1, 5); // odds
check(xs, |&x| x % 3 == 0, 4); // multiple of 3
check(xs, |&x| x % 4 == 0, 3); // multiple of 4
check(xs, |&x| x % 5 == 0, 2); // multiple of 5
check(xs, |&x| x < 3, 3); // small
check(xs, |&x| x > 6, 3); // large
}
2 changes: 2 additions & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#![feature(slice_partition_dedup)]
#![feature(int_error_matching)]
#![feature(const_fn)]
#![feature(iter_partition_in_place)]
#![feature(iter_is_partitioned)]
#![warn(rust_2018_idioms)]

extern crate test;
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1303,15 +1303,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}

// PGO does not work reliably with panic=unwind on Windows. Let's make it
// an error to combine the two for now. It always runs into an assertions
// a warning to combine the two for now. It always runs into an assertions
// if LLVM is built with assertions, but without assertions it sometimes
// does not crash and will probably generate a corrupted binary.
if sess.opts.cg.profile_generate.enabled() &&
sess.target.target.options.is_like_msvc &&
sess.panic_strategy() == PanicStrategy::Unwind {
sess.err("Profile-guided optimization does not yet work in conjunction \
with `-Cpanic=unwind` on Windows when targeting MSVC. \
See https://github.com/rust-lang/rust/issues/61002 for details.");
sess.warn("Profile-guided optimization does not yet work in conjunction \
with `-Cpanic=unwind` on Windows when targeting MSVC. \
See https://github.com/rust-lang/rust/issues/61002 for details.");
}
}

Expand Down
64 changes: 35 additions & 29 deletions src/librustc_codegen_llvm/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ trait ArgAttributeExt {
impl ArgAttributeExt for ArgAttribute {
fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
for_each_kind!(self, f,
ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
}
}

pub trait ArgAttributesExt {
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value);
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value);
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
}

impl ArgAttributesExt for ArgAttributes {
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
Expand All @@ -65,11 +65,14 @@ impl ArgAttributesExt for ArgAttributes {
idx.as_uint(),
align.bytes() as u32);
}
if regular.contains(ArgAttribute::ByVal) {
llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
}
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
}
}

fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
Expand All @@ -90,6 +93,9 @@ impl ArgAttributesExt for ArgAttributes {
idx.as_uint(),
align.bytes() as u32);
}
if regular.contains(ArgAttribute::ByVal) {
llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
}
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
}
}
Expand Down Expand Up @@ -298,7 +304,7 @@ pub trait FnTypeLlvmExt<'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_llfn(&self, llfn: &'ll Value);
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}

Expand Down Expand Up @@ -384,51 +390,51 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
}
}

fn apply_attrs_llfn(&self, llfn: &'ll Value) {
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
let mut i = 0;
let mut apply = |attrs: &ArgAttributes| {
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
i += 1;
};
match self.ret.mode {
PassMode::Direct(ref attrs) => {
attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
}
PassMode::Indirect(ref attrs, _) => apply(attrs),
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
_ => {}
}
for arg in &self.args {
if arg.pad.is_some() {
apply(&ArgAttributes::new());
apply(&ArgAttributes::new(), None);
}
match arg.mode {
PassMode::Ignore(_) => {}
PassMode::Direct(ref attrs) |
PassMode::Indirect(ref attrs, None) => apply(attrs),
PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(cx))),
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
apply(attrs);
apply(extra_attrs);
apply(attrs, None);
apply(extra_attrs, None);
}
PassMode::Pair(ref a, ref b) => {
apply(a);
apply(b);
apply(a, None);
apply(b, None);
}
PassMode::Cast(_) => apply(&ArgAttributes::new()),
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
}
}
}

fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
let mut i = 0;
let mut apply = |attrs: &ArgAttributes| {
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
i += 1;
};
match self.ret.mode {
PassMode::Direct(ref attrs) => {
attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite);
attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
}
PassMode::Indirect(ref attrs, _) => apply(attrs),
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
_ => {}
}
if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi {
Expand All @@ -446,21 +452,21 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
}
for arg in &self.args {
if arg.pad.is_some() {
apply(&ArgAttributes::new());
apply(&ArgAttributes::new(), None);
}
match arg.mode {
PassMode::Ignore(_) => {}
PassMode::Direct(ref attrs) |
PassMode::Indirect(ref attrs, None) => apply(attrs),
PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(bx))),
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
apply(attrs);
apply(extra_attrs);
apply(attrs, None);
apply(extra_attrs, None);
}
PassMode::Pair(ref a, ref b) => {
apply(a);
apply(b);
apply(a, None);
apply(b, None);
}
PassMode::Cast(_) => apply(&ArgAttributes::new()),
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
const_cstr!("probe-stack"), const_cstr!("__rust_probestack"));
}

fn translate_obsolete_target_features(feature: &str) -> &str {
const LLVM9_FEATURE_CHANGES: &[(&str, &str)] = &[
("+fp-only-sp", "-fp64"),
("-fp-only-sp", "+fp64"),
("+d16", "-d32"),
("-d16", "+d32"),
];
if llvm_util::get_major_version() >= 9 {
for &(old, new) in LLVM9_FEATURE_CHANGES {
if feature == old {
return new;
}
}
} else {
for &(old, new) in LLVM9_FEATURE_CHANGES {
if feature == new {
return old;
}
}
}
feature
}

pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
const RUSTC_SPECIFIC_FEATURES: &[&str] = &[
"crt-static",
Expand All @@ -129,6 +152,7 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
sess.target.target.options.features.split(',')
.chain(cmdline)
.filter(|l| !l.is_empty())
.map(translate_obsolete_target_features)
}

pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_codegen_llvm/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.const_uint(self.type_i8(), i as u64)
}

fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value {
unsafe { llvm::LLVMConstReal(t, val) }
}

fn const_struct(
&self,
elts: &[&'ll Value],
Expand Down
Loading

0 comments on commit 0324a2b

Please sign in to comment.