fortrangoingonforty/armfortas / 5b3eccb

Browse files

Test ALLOCATE source= from a strided rank-1 section copies via stride

Authored by espadonne
Committed by mfwolffe
SHA
5b3eccb23cf7bc75b33113c95fc139260d9141e4
Parents
fad3454
Tree
bf8bb6b

1 changed file

StatusFile+-
M tests/cli_driver.rs 39 0
tests/cli_driver.rsmodified
@@ -28623,6 +28623,45 @@ fn cmplx_whole_array_with_kind_keyword_returns_correct_kind_descriptor() {
2862328623
     let _ = std::fs::remove_file(&src);
2862428624
 }
2862528625
 
28626
+#[test]
28627
+fn allocate_source_from_strided_section_walks_per_element() {
28628
+    // F2018 §9.7.1.2: ALLOCATE(dest, source = strided_section) must
28629
+    // populate dest by reading the source per-element via the
28630
+    // section's per-dim memory stride, not by a flat memcpy of
28631
+    // total_bytes from source base. afs_copy_array_data was doing
28632
+    // ptr::copy(source.base_addr, dest.base_addr, total_bytes), which
28633
+    // for a section like `idx(2, 1:n)` (stride 2 between adjacent
28634
+    // dim-0=2 picks) read consecutive bytes including dim-0=1 entries.
28635
+    // Surfaced inside stdlib_sparse_conversion's coo2csr_dp at line
28636
+    // 426: `allocate(CSR%col, source = COO%index(2, 1:nnz))` populated
28637
+    // CSR%col with row indices instead of column indices, so spmv
28638
+    // walked vec_x past its declared bounds.
28639
+    let src = write_program(
28640
+        "program p\n  implicit none\n  integer, allocatable :: idx(:,:)\n  integer, allocatable :: col(:)\n  integer :: i, n\n  n = 8\n  allocate(idx(2, n), source=0)\n  do i = 1, n\n    idx(1, i) = (i-1) / 2 + 1\n    idx(2, i) = mod(i-1, 2) + 1\n  end do\n  allocate(col(n), source = idx(2, 1:n))\n  do i = 1, n\n    if (col(i) /= idx(2, i)) error stop 1\n  end do\n  print *, 'ok'\nend program\n",
28641
+        "f90",
28642
+    );
28643
+    let out = unique_path("alloc_source_strided_section", "bin");
28644
+    let compile = Command::new(compiler("armfortas"))
28645
+        .args([src.to_str().unwrap(), "-o", out.to_str().unwrap()])
28646
+        .output()
28647
+        .expect("alloc-source strided compile failed to spawn");
28648
+    assert!(
28649
+        compile.status.success(),
28650
+        "alloc-source strided compile failed: {}",
28651
+        String::from_utf8_lossy(&compile.stderr)
28652
+    );
28653
+    let run = Command::new(&out).output().expect("run failed");
28654
+    assert!(
28655
+        run.status.success() && String::from_utf8_lossy(&run.stdout).contains("ok"),
28656
+        "alloc-source strided run failed: status={:?} stdout={} stderr={}",
28657
+        run.status,
28658
+        String::from_utf8_lossy(&run.stdout),
28659
+        String::from_utf8_lossy(&run.stderr)
28660
+    );
28661
+    let _ = std::fs::remove_file(&out);
28662
+    let _ = std::fs::remove_file(&src);
28663
+}
28664
+
2862628665
 #[test]
2862728666
 fn random_number_on_array_fills_every_element() {
2862828667
     // F2018 §16.9.171: RANDOM_NUMBER(harvest) fills harvest with