Skip to content

Commit 0324a2b

Browse files
committed
Auto merge of #62555 - Centril:rollup-ti46adx, r=Centril
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
2 parents 3f435f6 + 6c0a406 commit 0324a2b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+551
-180
lines changed

src/libcore/iter/traits/iterator.rs

+100
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,11 @@ pub trait Iterator {
14721472
/// `partition()` returns a pair, all of the elements for which it returned
14731473
/// `true`, and all of the elements for which it returned `false`.
14741474
///
1475+
/// See also [`is_partitioned()`] and [`partition_in_place()`].
1476+
///
1477+
/// [`is_partitioned()`]: #method.is_partitioned
1478+
/// [`partition_in_place()`]: #method.partition_in_place
1479+
///
14751480
/// # Examples
14761481
///
14771482
/// Basic usage:
@@ -1506,6 +1511,101 @@ pub trait Iterator {
15061511
(left, right)
15071512
}
15081513

1514+
/// Reorder the elements of this iterator *in-place* according to the given predicate,
1515+
/// such that all those that return `true` precede all those that return `false`.
1516+
/// Returns the number of `true` elements found.
1517+
///
1518+
/// The relative order of partitioned items is not maintained.
1519+
///
1520+
/// See also [`is_partitioned()`] and [`partition()`].
1521+
///
1522+
/// [`is_partitioned()`]: #method.is_partitioned
1523+
/// [`partition()`]: #method.partition
1524+
///
1525+
/// # Examples
1526+
///
1527+
/// ```
1528+
/// #![feature(iter_partition_in_place)]
1529+
///
1530+
/// let mut a = [1, 2, 3, 4, 5, 6, 7];
1531+
///
1532+
/// // Partition in-place between evens and odds
1533+
/// let i = a.iter_mut().partition_in_place(|&n| n % 2 == 0);
1534+
///
1535+
/// assert_eq!(i, 3);
1536+
/// assert!(a[..i].iter().all(|&n| n % 2 == 0)); // evens
1537+
/// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds
1538+
/// ```
1539+
#[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")]
1540+
fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize
1541+
where
1542+
Self: Sized + DoubleEndedIterator<Item = &'a mut T>,
1543+
P: FnMut(&T) -> bool,
1544+
{
1545+
// FIXME: should we worry about the count overflowing? The only way to have more than
1546+
// `usize::MAX` mutable references is with ZSTs, which aren't useful to partition...
1547+
1548+
// These closure "factory" functions exist to avoid genericity in `Self`.
1549+
1550+
#[inline]
1551+
fn is_false<'a, T>(
1552+
predicate: &'a mut impl FnMut(&T) -> bool,
1553+
true_count: &'a mut usize,
1554+
) -> impl FnMut(&&mut T) -> bool + 'a {
1555+
move |x| {
1556+
let p = predicate(&**x);
1557+
*true_count += p as usize;
1558+
!p
1559+
}
1560+
}
1561+
1562+
#[inline]
1563+
fn is_true<T>(
1564+
predicate: &mut impl FnMut(&T) -> bool
1565+
) -> impl FnMut(&&mut T) -> bool + '_ {
1566+
move |x| predicate(&**x)
1567+
}
1568+
1569+
// Repeatedly find the first `false` and swap it with the last `true`.
1570+
let mut true_count = 0;
1571+
while let Some(head) = self.find(is_false(predicate, &mut true_count)) {
1572+
if let Some(tail) = self.rfind(is_true(predicate)) {
1573+
crate::mem::swap(head, tail);
1574+
true_count += 1;
1575+
} else {
1576+
break;
1577+
}
1578+
}
1579+
true_count
1580+
}
1581+
1582+
/// Checks if the elements of this iterator are partitioned according to the given predicate,
1583+
/// such that all those that return `true` precede all those that return `false`.
1584+
///
1585+
/// See also [`partition()`] and [`partition_in_place()`].
1586+
///
1587+
/// [`partition()`]: #method.partition
1588+
/// [`partition_in_place()`]: #method.partition_in_place
1589+
///
1590+
/// # Examples
1591+
///
1592+
/// ```
1593+
/// #![feature(iter_is_partitioned)]
1594+
///
1595+
/// assert!("Iterator".chars().is_partitioned(char::is_uppercase));
1596+
/// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase));
1597+
/// ```
1598+
#[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")]
1599+
fn is_partitioned<P>(mut self, mut predicate: P) -> bool
1600+
where
1601+
Self: Sized,
1602+
P: FnMut(Self::Item) -> bool,
1603+
{
1604+
// Either all items test `true`, or the first clause stops at `false`
1605+
// and we check that there are no more `true` items after that.
1606+
self.all(&mut predicate) || !self.any(predicate)
1607+
}
1608+
15091609
/// An iterator method that applies a function as long as it returns
15101610
/// successfully, producing a single, final value.
15111611
///

src/libcore/tests/iter.rs

+36
Original file line numberDiff line numberDiff line change
@@ -2460,3 +2460,39 @@ fn test_is_sorted() {
24602460
assert!(!["c", "bb", "aaa"].iter().is_sorted());
24612461
assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
24622462
}
2463+
2464+
#[test]
2465+
fn test_partition() {
2466+
fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) {
2467+
let i = xs.iter_mut().partition_in_place(p);
2468+
assert_eq!(expected, i);
2469+
assert!(xs[..i].iter().all(p));
2470+
assert!(!xs[i..].iter().any(p));
2471+
assert!(xs.iter().is_partitioned(p));
2472+
if i == 0 || i == xs.len() {
2473+
assert!(xs.iter().rev().is_partitioned(p));
2474+
} else {
2475+
assert!(!xs.iter().rev().is_partitioned(p));
2476+
}
2477+
}
2478+
2479+
check(&mut [], |_| true, 0);
2480+
check(&mut [], |_| false, 0);
2481+
2482+
check(&mut [0], |_| true, 1);
2483+
check(&mut [0], |_| false, 0);
2484+
2485+
check(&mut [-1, 1], |&x| x > 0, 1);
2486+
check(&mut [-1, 1], |&x| x < 0, 1);
2487+
2488+
let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2489+
check(xs, |_| true, 10);
2490+
check(xs, |_| false, 0);
2491+
check(xs, |&x| x % 2 == 0, 5); // evens
2492+
check(xs, |&x| x % 2 == 1, 5); // odds
2493+
check(xs, |&x| x % 3 == 0, 4); // multiple of 3
2494+
check(xs, |&x| x % 4 == 0, 3); // multiple of 4
2495+
check(xs, |&x| x % 5 == 0, 2); // multiple of 5
2496+
check(xs, |&x| x < 3, 3); // small
2497+
check(xs, |&x| x > 6, 3); // large
2498+
}

src/libcore/tests/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#![feature(slice_partition_dedup)]
3232
#![feature(int_error_matching)]
3333
#![feature(const_fn)]
34+
#![feature(iter_partition_in_place)]
35+
#![feature(iter_is_partitioned)]
3436
#![warn(rust_2018_idioms)]
3537

3638
extern crate test;

src/librustc/session/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1303,15 +1303,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
13031303
}
13041304

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

src/librustc_codegen_llvm/abi.rs

+35-29
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ trait ArgAttributeExt {
3434
impl ArgAttributeExt for ArgAttribute {
3535
fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
3636
for_each_kind!(self, f,
37-
ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
37+
NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
3838
}
3939
}
4040

4141
pub trait ArgAttributesExt {
42-
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value);
43-
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value);
42+
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
43+
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
4444
}
4545

4646
impl ArgAttributesExt for ArgAttributes {
47-
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
47+
fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
4848
let mut regular = self.regular;
4949
unsafe {
5050
let deref = self.pointee_size.bytes();
@@ -65,11 +65,14 @@ impl ArgAttributesExt for ArgAttributes {
6565
idx.as_uint(),
6666
align.bytes() as u32);
6767
}
68+
if regular.contains(ArgAttribute::ByVal) {
69+
llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
70+
}
6871
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
6972
}
7073
}
7174

72-
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
75+
fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
7376
let mut regular = self.regular;
7477
unsafe {
7578
let deref = self.pointee_size.bytes();
@@ -90,6 +93,9 @@ impl ArgAttributesExt for ArgAttributes {
9093
idx.as_uint(),
9194
align.bytes() as u32);
9295
}
96+
if regular.contains(ArgAttribute::ByVal) {
97+
llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
98+
}
9399
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
94100
}
95101
}
@@ -298,7 +304,7 @@ pub trait FnTypeLlvmExt<'tcx> {
298304
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
299305
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
300306
fn llvm_cconv(&self) -> llvm::CallConv;
301-
fn apply_attrs_llfn(&self, llfn: &'ll Value);
307+
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
302308
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
303309
}
304310

@@ -384,51 +390,51 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
384390
}
385391
}
386392

387-
fn apply_attrs_llfn(&self, llfn: &'ll Value) {
393+
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
388394
let mut i = 0;
389-
let mut apply = |attrs: &ArgAttributes| {
390-
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
395+
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
396+
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
391397
i += 1;
392398
};
393399
match self.ret.mode {
394400
PassMode::Direct(ref attrs) => {
395-
attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
401+
attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
396402
}
397-
PassMode::Indirect(ref attrs, _) => apply(attrs),
403+
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
398404
_ => {}
399405
}
400406
for arg in &self.args {
401407
if arg.pad.is_some() {
402-
apply(&ArgAttributes::new());
408+
apply(&ArgAttributes::new(), None);
403409
}
404410
match arg.mode {
405411
PassMode::Ignore(_) => {}
406412
PassMode::Direct(ref attrs) |
407-
PassMode::Indirect(ref attrs, None) => apply(attrs),
413+
PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(cx))),
408414
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
409-
apply(attrs);
410-
apply(extra_attrs);
415+
apply(attrs, None);
416+
apply(extra_attrs, None);
411417
}
412418
PassMode::Pair(ref a, ref b) => {
413-
apply(a);
414-
apply(b);
419+
apply(a, None);
420+
apply(b, None);
415421
}
416-
PassMode::Cast(_) => apply(&ArgAttributes::new()),
422+
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
417423
}
418424
}
419425
}
420426

421427
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
422428
let mut i = 0;
423-
let mut apply = |attrs: &ArgAttributes| {
424-
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
429+
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
430+
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
425431
i += 1;
426432
};
427433
match self.ret.mode {
428434
PassMode::Direct(ref attrs) => {
429-
attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite);
435+
attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
430436
}
431-
PassMode::Indirect(ref attrs, _) => apply(attrs),
437+
PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
432438
_ => {}
433439
}
434440
if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi {
@@ -446,21 +452,21 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
446452
}
447453
for arg in &self.args {
448454
if arg.pad.is_some() {
449-
apply(&ArgAttributes::new());
455+
apply(&ArgAttributes::new(), None);
450456
}
451457
match arg.mode {
452458
PassMode::Ignore(_) => {}
453459
PassMode::Direct(ref attrs) |
454-
PassMode::Indirect(ref attrs, None) => apply(attrs),
460+
PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(bx))),
455461
PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
456-
apply(attrs);
457-
apply(extra_attrs);
462+
apply(attrs, None);
463+
apply(extra_attrs, None);
458464
}
459465
PassMode::Pair(ref a, ref b) => {
460-
apply(a);
461-
apply(b);
466+
apply(a, None);
467+
apply(b, None);
462468
}
463-
PassMode::Cast(_) => apply(&ArgAttributes::new()),
469+
PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
464470
}
465471
}
466472

src/librustc_codegen_llvm/attributes.rs

+24
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,29 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
119119
const_cstr!("probe-stack"), const_cstr!("__rust_probestack"));
120120
}
121121

122+
fn translate_obsolete_target_features(feature: &str) -> &str {
123+
const LLVM9_FEATURE_CHANGES: &[(&str, &str)] = &[
124+
("+fp-only-sp", "-fp64"),
125+
("-fp-only-sp", "+fp64"),
126+
("+d16", "-d32"),
127+
("-d16", "+d32"),
128+
];
129+
if llvm_util::get_major_version() >= 9 {
130+
for &(old, new) in LLVM9_FEATURE_CHANGES {
131+
if feature == old {
132+
return new;
133+
}
134+
}
135+
} else {
136+
for &(old, new) in LLVM9_FEATURE_CHANGES {
137+
if feature == new {
138+
return old;
139+
}
140+
}
141+
}
142+
feature
143+
}
144+
122145
pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
123146
const RUSTC_SPECIFIC_FEATURES: &[&str] = &[
124147
"crt-static",
@@ -129,6 +152,7 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
129152
sess.target.target.options.features.split(',')
130153
.chain(cmdline)
131154
.filter(|l| !l.is_empty())
155+
.map(translate_obsolete_target_features)
132156
}
133157

134158
pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {

src/librustc_codegen_llvm/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
249249
self.const_uint(self.type_i8(), i as u64)
250250
}
251251

252+
fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value {
253+
unsafe { llvm::LLVMConstReal(t, val) }
254+
}
255+
252256
fn const_struct(
253257
&self,
254258
elts: &[&'ll Value],

0 commit comments

Comments
 (0)