From bd0aae92dc76d9336cf09c097ac5a49fd619da44 Mon Sep 17 00:00:00 2001
From: Erik Desjardins <erikdesjardins@users.noreply.github.com>
Date: Sun, 11 Jun 2023 00:04:53 -0400
Subject: [PATCH] cg_llvm: use index-based loop in write_operand_repeatedly

This is easier for LLVM to analyze.
---
 compiler/rustc_codegen_llvm/src/builder.rs | 20 ++++++--------------
 tests/codegen/issues/issue-111603.rs       | 12 ++++++++++++
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index b4aa001547c..43258078bd7 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -572,8 +572,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     ) {
         let zero = self.const_usize(0);
         let count = self.const_usize(count);
-        let start = dest.project_index(self, zero).llval;
-        let end = dest.project_index(self, count).llval;
 
         let header_bb = self.append_sibling_block("repeat_loop_header");
         let body_bb = self.append_sibling_block("repeat_loop_body");
@@ -582,24 +580,18 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         self.br(header_bb);
 
         let mut header_bx = Self::build(self.cx, header_bb);
-        let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
+        let i = header_bx.phi(self.val_ty(zero), &[zero], &[self.llbb()]);
 
-        let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
+        let keep_going = header_bx.icmp(IntPredicate::IntULT, i, count);
         header_bx.cond_br(keep_going, body_bb, next_bb);
 
         let mut body_bx = Self::build(self.cx, body_bb);
-        let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
-        cg_elem
-            .val
-            .store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
+        let dest_elem = dest.project_index(&mut body_bx, i);
+        cg_elem.val.store(&mut body_bx, dest_elem);
 
-        let next = body_bx.inbounds_gep(
-            self.backend_type(cg_elem.layout),
-            current,
-            &[self.const_usize(1)],
-        );
+        let next = body_bx.unchecked_uadd(i, self.const_usize(1));
         body_bx.br(header_bb);
-        header_bx.add_incoming_to_phi(current, next, body_bb);
+        header_bx.add_incoming_to_phi(i, next, body_bb);
 
         *self = Self::build(self.cx, next_bb);
     }
diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs
index 90b3c314d2f..06429ed3fa9 100644
--- a/tests/codegen/issues/issue-111603.rs
+++ b/tests/codegen/issues/issue-111603.rs
@@ -5,6 +5,18 @@
 
 use std::sync::Arc;
 
+// CHECK-LABEL: @new_from_array
+#[no_mangle]
+pub fn new_from_array(x: u64) -> Arc<[u64]> {
+    // Ensure that we only generate one alloca for the array.
+
+    // CHECK: alloca
+    // CHECK-SAME: [1000 x i64]
+    // CHECK-NOT: alloca
+    let array = [x; 1000];
+    Arc::new(array)
+}
+
 // CHECK-LABEL: @new_uninit
 #[no_mangle]
 pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> {