Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #62555

Merged
merged 26 commits into from
Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
515da72
Target::arch can take more than listed options
fintelia Jul 1, 2019
7aaf0de
Add a test for `$crate` inside macro invocation
petrochenkov Jul 3, 2019
4344a90
Pretty-print `$crate` as `crate`/`::my_crate` in tokens
petrochenkov Jul 3, 2019
3997507
Resolve `$crate` in all hygienic contexts for pretty-pringing
petrochenkov Jul 5, 2019
60f1449
Add Iterator::partition_mut() and is_partitioned()
cuviper Jul 1, 2019
cdeec0a
Capitalize example comment
cuviper Jul 1, 2019
cd0ebc4
Rename partition_mut to partition_in_place
cuviper Jul 1, 2019
0492f97
Return the true count from partition_in_place
cuviper Jul 9, 2019
265e3a6
Unit test Iterator::partition_in_place and is_partitioned
cuviper Jul 9, 2019
4cb67c0
Add a test case with `$crate` from other crate
petrochenkov Jul 9, 2019
04304fc
Pass GUIDPreservedSymbols to thinLTOResolvePrevailingInIndex()
nikic Jul 6, 2019
eb33822
Pass type to byval attributes
nikic Jul 6, 2019
b57c499
Translate target features for LLVM 9
nikic Jul 7, 2019
3170b62
Use new feature names in target feature lists
nikic Jul 7, 2019
5324b42
Add function pointer alignment to ARM/Thumb data layout
nikic Jul 7, 2019
8789c9e
Strip function pointer alignment for older LLVM versions
nikic Jul 7, 2019
5c95f5f
Fix float add/mul reduction codegen
nikic Jul 7, 2019
ac56025
Adjust codegen tests for DISPFlagMainSubprogram
nikic Jul 7, 2019
74a39a3
Emit warning when trying to use PGO in conjunction with unwinding on …
EricRahm Jun 14, 2019
4c22e48
Tracking issue 62543 for iter_partition_in_place
cuviper Jul 9, 2019
7171c83
Tracking issue 62544 for iter_is_partitioned
cuviper Jul 9, 2019
3c3e375
Rollup merge of #61853 - EricRahm:use_warning, r=varkor
Centril Jul 10, 2019
b14b20c
Rollup merge of #62278 - cuviper:iter-partition, r=alexcrichton
Centril Jul 10, 2019
1e48be9
Rollup merge of #62283 - fintelia:patch-5, r=Mark-Simulacrum
Centril Jul 10, 2019
fe26fc9
Rollup merge of #62393 - petrochenkov:notto-disu, r=Mark-Simulacrum
Centril Jul 10, 2019
6c0a406
Rollup merge of #62474 - nikic:update-llvm, r=alexcrichton
Centril Jul 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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