about summary refs log tree commit diff
path: root/src/test/codegen
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev+love@gmail.com>2022-11-20 13:15:59 +0900
committerGitHub <noreply@github.com>2022-11-20 13:15:59 +0900
commit785237d3924d4fb7b23803c964972dce82de2161 (patch)
treec3b5a12cfff05df99d15ec98e86583d3a4045dee /src/test/codegen
parente69b84204aecf27fe18ada467f78c83b788b80e4 (diff)
parent71bb200225f0164940acc21f1fb647c8155f1706 (diff)
downloadrust-785237d3924d4fb7b23803c964972dce82de2161.tar.gz
rust-785237d3924d4fb7b23803c964972dce82de2161.zip
Rollup merge of #104435 - scottmcm:iter-repeat-n, r=thomcc
`VecDeque::resize` should re-use the buffer in the passed-in element

Today it always copies it for *every* appended element, but one of those clones is avoidable.

This adds `iter::repeat_n` (https://github.com/rust-lang/rust/issues/104434) as the primitive needed to do this.  If this PR is acceptable, I'll also use this in `Vec` rather than its custom `ExtendElement` type & infrastructure that is harder to share between multiple different containers:

https://github.com/rust-lang/rust/blob/101e1822c3e54e63996c8aaa014d55716f3937eb/library/alloc/src/vec/mod.rs#L2479-L2492
Diffstat (limited to 'src/test/codegen')
-rw-r--r--src/test/codegen/iter-repeat-n-trivial-drop.rs56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/test/codegen/iter-repeat-n-trivial-drop.rs b/src/test/codegen/iter-repeat-n-trivial-drop.rs
new file mode 100644
index 00000000000..20e1d9b4d59
--- /dev/null
+++ b/src/test/codegen/iter-repeat-n-trivial-drop.rs
@@ -0,0 +1,56 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(iter_repeat_n)]
+
+#[derive(Clone)]
+pub struct NotCopy(u16);
+
+impl Drop for NotCopy {
+    fn drop(&mut self) {}
+}
+
+// For a type where `Drop::drop` doesn't do anything observable and a clone is the
+// same as a move, make sure that the extra case for the last item disappears.
+
+#[no_mangle]
+// CHECK-LABEL: @iter_repeat_n_next
+pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCopy> {
+    // CHECK-NEXT: start:
+    // CHECK-NOT: br
+    // CHECK: %[[COUNT:.+]] = load i64
+    // CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0
+    // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]]
+
+    // CHECK: [[NOT_EMPTY]]:
+    // CHECK-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1
+    // CHECK-NEXT: store i64 %[[DEC]]
+    // CHECK-NOT: br
+    // CHECK: %[[VAL:.+]] = load i16
+    // CHECK-NEXT: br label %[[EMPTY]]
+
+    // CHECK: [[EMPTY]]:
+    // CHECK-NOT: br
+    // CHECK: phi i16 [ undef, %start ], [ %[[VAL]], %[[NOT_EMPTY]] ]
+    // CHECK-NOT: br
+    // CHECK: ret
+
+    it.next()
+}
+
+// And as a result, using the iterator can optimize without special cases for
+// the last iteration, like `memset`ing all the items in one call.
+
+#[no_mangle]
+// CHECK-LABEL: @vec_extend_via_iter_repeat_n
+pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
+    // CHECK: %[[ADDR:.+]] = tail call dereferenceable_or_null(1234) ptr @__rust_alloc(i64 1234, i64 1)
+    // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234,
+
+    let n = 1234_usize;
+    let mut v = Vec::with_capacity(n);
+    v.extend(std::iter::repeat_n(42_u8, n));
+    v
+}