about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-12-21 23:12:15 +0100
committerNikita Popov <nikita.ppv@gmail.com>2018-12-21 23:51:55 +0100
commit097d39d8ecb2d8aa828393c66e85716081188793 (patch)
treeaa2379ca26f87947862b7528cd3087e04c092f27
parent6d34ec18c7d7e574553f6347ecf08e1e1c45c13d (diff)
downloadrust-097d39d8ecb2d8aa828393c66e85716081188793.tar.gz
rust-097d39d8ecb2d8aa828393c66e85716081188793.zip
Fix alignment for array indexing
We need to reduce the alignment with the used offset. If the offset
isn't known, we need to reduce with the element size to support
arbitrary offsets.
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs13
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs3
-rw-r--r--src/test/codegen/issue-56927.rs44
-rw-r--r--src/test/codegen/packed.rs36
4 files changed, 93 insertions, 3 deletions
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 90aa9f6cbc7..5fad4a24b26 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -335,11 +335,20 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
         bx: &mut Bx,
         llindex: V
     ) -> Self {
+        // Statically compute the offset if we can, otherwise just use the element size,
+        // as this will yield the lowest alignment.
+        let layout = self.layout.field(bx, 0);
+        let offset = if bx.is_const_integral(llindex) {
+            layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size)
+        } else {
+            layout.size
+        };
+
         PlaceRef {
             llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]),
             llextra: None,
-            layout: self.layout.field(bx.cx(), 0),
-            align: self.align
+            layout,
+            align: self.align.restrict_for_offset(offset),
         }
     }
 
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index c932ffd1c1b..052342dd759 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -131,8 +131,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
                 header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
 
+                let align = dest.align.restrict_for_offset(dest.layout.field(bx.cx(), 0).size);
                 cg_elem.val.store(&mut body_bx,
-                    PlaceRef::new_sized(current, cg_elem.layout, dest.align));
+                    PlaceRef::new_sized(current, cg_elem.layout, align));
 
                 let next = body_bx.inbounds_gep(current, &[bx.cx().const_usize(1)]);
                 body_bx.br(header_bx.llbb());
diff --git a/src/test/codegen/issue-56927.rs b/src/test/codegen/issue-56927.rs
new file mode 100644
index 00000000000..0544ff86aac
--- /dev/null
+++ b/src/test/codegen/issue-56927.rs
@@ -0,0 +1,44 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type="rlib"]
+use std::usize;
+
+#[repr(align(16))]
+pub struct S {
+    arr: [u32; 4],
+}
+
+// CHECK-LABEL: @test1
+// CHECK: store i32 0, i32* %{{.+}}, align 16
+// CHECK: store i32 1, i32* %{{.+}}, align 4
+// CHECK: store i32 2, i32* %{{.+}}, align 8
+// CHECK: store i32 3, i32* %{{.+}}, align 4
+#[no_mangle]
+pub fn test1(s: &mut S) {
+    s.arr[0] = 0;
+    s.arr[1] = 1;
+    s.arr[2] = 2;
+    s.arr[3] = 3;
+}
+
+// CHECK-LABEL: @test2
+// CHECK: store i32 4, i32* %{{.+}}, align 4
+#[allow(const_err)]
+#[no_mangle]
+pub fn test2(s: &mut S) {
+    s.arr[usize::MAX / 4 + 1] = 4;
+}
+
+// CHECK-LABEL: @test3
+// CHECK: store i32 5, i32* %{{.+}}, align 4
+#[no_mangle]
+pub fn test3(s: &mut S, i: usize) {
+    s.arr[i] = 5;
+}
+
+// CHECK-LABEL: @test4
+// CHECK: store i32 6, i32* %{{.+}}, align 4
+#[no_mangle]
+pub fn test4(s: &mut S) {
+    s.arr = [6; 4];
+}
diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs
index b50f5b6f16f..e60051de559 100644
--- a/src/test/codegen/packed.rs
+++ b/src/test/codegen/packed.rs
@@ -84,6 +84,42 @@ pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
     BigPacked2 { dealign: 0, data: f() }
 }
 
+// CHECK-LABEL: @write_packed_array1
+// CHECK: store i32 0, i32* %{{.+}}, align 1
+// CHECK: store i32 1, i32* %{{.+}}, align 1
+// CHECK: store i32 2, i32* %{{.+}}, align 1
+#[no_mangle]
+pub fn write_packed_array1(p: &mut BigPacked1) {
+    p.data.0[0] = 0;
+    p.data.0[1] = 1;
+    p.data.0[2] = 2;
+}
+
+// CHECK-LABEL: @write_packed_array2
+// CHECK: store i32 0, i32* %{{.+}}, align 2
+// CHECK: store i32 1, i32* %{{.+}}, align 2
+// CHECK: store i32 2, i32* %{{.+}}, align 2
+#[no_mangle]
+pub fn write_packed_array2(p: &mut BigPacked2) {
+    p.data.0[0] = 0;
+    p.data.0[1] = 1;
+    p.data.0[2] = 2;
+}
+
+// CHECK-LABEL: @repeat_packed_array1
+// CHECK: store i32 42, i32* %{{.+}}, align 1
+#[no_mangle]
+pub fn repeat_packed_array1(p: &mut BigPacked1) {
+    p.data.0 = [42; 8];
+}
+
+// CHECK-LABEL: @repeat_packed_array2
+// CHECK: store i32 42, i32* %{{.+}}, align 2
+#[no_mangle]
+pub fn repeat_packed_array2(p: &mut BigPacked2) {
+    p.data.0 = [42; 8];
+}
+
 #[repr(packed)]
 #[derive(Copy, Clone)]
 pub struct Packed1Pair(u8, u32);