fortrangoingonforty/armfortas / f9a892d

Browse files

Capture compiler updates and formatting sweep

Authored by espadonne
SHA
f9a892d12375393e56514233185e348f72f5698b
Parents
b37c32f
Tree
564df24

112 changed files

StatusFile+-
M afs-as 1 1
M afs-ld 1 1
M runtime/src/array.rs 407 138
M runtime/src/descriptor.rs 16 4
M runtime/src/format.rs 474 111
M runtime/src/io_system.rs 1146 410
M runtime/src/lib.rs 5 5
M runtime/src/mem.rs 9 14
M runtime/src/system.rs 169 45
M src/ast/decl.rs 19 31
M src/ast/expr.rs 70 72
M src/ast/mod.rs 1 1
M src/ast/stmt.rs 132 37
M src/ast/unit.rs 5 5
M src/codegen/linearscan.rs 147 54
M src/codegen/liveness.rs 54 22
M src/codegen/mod.rs 4 4
M src/codegen/peephole.rs 125 33
M src/codegen/regalloc.rs 40 22
M src/codegen/tailcall.rs 69 45
M src/driver/dep_scan.rs 84 19
M src/driver/diag.rs 16 9
M src/driver/mod.rs 105 48
M src/ir/builder.rs 143 39
M src/ir/inst.rs 90 41
M src/ir/mod.rs 3 3
M src/ir/printer.rs 141 36
M src/ir/types.rs 24 7
M src/ir/verify.rs 130 54
M src/ir/walk.rs 268 122
M src/lexer/mod.rs 644 211
M src/opt/alias.rs 103 32
M src/opt/audit_tests.rs 835 228
M src/opt/bce.rs 106 48
M src/opt/call_resolve.rs 9 5
M src/opt/callgraph.rs 37 17
M src/opt/const_arg.rs 81 17
M src/opt/const_fold.rs 217 74
M src/opt/const_prop.rs 42 11
M src/opt/cse.rs 123 45
M src/opt/dce.rs 125 42
M src/opt/dead_arg.rs 31 9
M src/opt/dead_func.rs 25 10
M src/opt/dep_analysis.rs 139 49
M src/opt/dse.rs 75 41
M src/opt/fast_math.rs 35 14
M src/opt/fission.rs 78 29
M src/opt/fusion.rs 123 52
M src/opt/global_lsf.rs 35 19
M src/opt/gvn.rs 324 113
M src/opt/inline.rs 148 137
M src/opt/interchange.rs 128 43
M src/opt/licm.rs 173 62
M src/opt/loop_tree.rs 128 53
M src/opt/loop_utils.rs 85 68
M src/opt/lsf.rs 236 76
M src/opt/mem2reg.rs 802 308
M src/opt/mod.rs 28 28
M src/opt/pass.rs 23 10
M src/opt/peel.rs 97 38
M src/opt/pipeline.rs 39 26
M src/opt/preheader.rs 81 36
M src/opt/return_prop.rs 68 19
M src/opt/simplify_cfg.rs 58 20
M src/opt/sroa.rs 69 25
M src/opt/strength_reduce.rs 194 54
M src/opt/unroll.rs 343 185
M src/opt/unswitch.rs 121 51
M src/opt/util.rs 4 14
M src/opt/vectorize.rs 170 51
M src/parser/decl.rs 449 124
M src/parser/expr.rs 255 105
M src/parser/mod.rs 22 7
M src/parser/stmt.rs 13 6
M src/preprocess/mod.rs 278 76
M src/sema/intrinsic_modules.rs 118 48
M src/sema/mod.rs 4 4
M src/sema/symtab.rs 79 23
M src/sema/type_layout.rs 190 93
M src/sema/types.rs 779 302
M src/sema/validate.rs 606 273
M src/testing.rs 29 20
M tests/artifact_audit_29_10.rs 10 2
M tests/claims_audit_29_11.rs 11 3
M tests/determinism_sweep.rs 23 9
M tests/fortran_alias_licm.rs 8 6
M tests/fuzz_smoke.rs 14 6
M tests/gvn_dse_audit_29_11.rs 2 8
M tests/i128_cross_object.rs 35 9
M tests/i128_formatted_read.rs 64 13
M tests/i128_gates.rs 15 3
M tests/i128_high_opt.rs 5 1
M tests/i128_internal_io.rs 94 20
M tests/i128_memory_backend.rs 15 3
M tests/i128_o1.rs 10 2
M tests/i128_o2.rs 5 1
M tests/i128_runtime_io.rs 24 7
M tests/i128_runtime_read.rs 9 3
M tests/i128_stack_args.rs 23 4
M tests/incremental.rs 23 10
M tests/ipo_const_arg.rs 25 11
M tests/ipo_dead_arg.rs 31 12
M tests/ipo_return_prop.rs 13 9
M tests/licm_lsf_audit_29_11.rs 7 6
M tests/multifile.rs 44 17
M tests/multifile_gen.rs 55 18
M tests/ofast_fast_math.rs 17 4
M tests/opt_audit_29_11.rs 5 4
M tests/program_entry_audit.rs 4 1
M tests/pure_call_reuse.rs 5 5
M tests/pure_dead_call_elim.rs 3 1
M tests/vectorize_do_loop.rs 4 1
afs-asmodified
2 lines changed — click to load
@@ -1,1 +1,1 @@
1
-Subproject commit 67061bd8688fcbe3a633c87557913bed9eeddba6
1
+Subproject commit 36a2e46e175f530b8884242fed09c8b2b79bfda8
afs-ldmodified
2 lines changed — click to load
@@ -1,1 +1,1 @@
1
-Subproject commit 5e99aa0c7b24dd10a3ad09de3d11823e07bc4839
1
+Subproject commit 20d5047b0a9875d243f48f48b5ecfd70cc5d046a
runtime/src/array.rsmodified
1060 lines changed — click to load
@@ -611,7 +611,9 @@ pub extern "C" fn afs_fill_i32(dest: *mut i32, n: i64, value: i32) {
611611
     if len == 0 {
612612
         return;
613613
     }
614
-    unsafe { fill_i32_impl(dest, len, value); }
614
+    unsafe {
615
+        fill_i32_impl(dest, len, value);
616
+    }
615617
 }
616618
 
617619
 #[no_mangle]
@@ -623,7 +625,9 @@ pub extern "C" fn afs_fill_f32(dest: *mut f32, n: i64, value: f32) {
623625
     if len == 0 {
624626
         return;
625627
     }
626
-    unsafe { fill_f32_impl(dest, len, value); }
628
+    unsafe {
629
+        fill_f32_impl(dest, len, value);
630
+    }
627631
 }
628632
 
629633
 #[no_mangle]
@@ -635,7 +639,9 @@ pub extern "C" fn afs_fill_f64(dest: *mut f64, n: i64, value: f64) {
635639
     if len == 0 {
636640
         return;
637641
     }
638
-    unsafe { fill_f64_impl(dest, len, value); }
642
+    unsafe {
643
+        fill_f64_impl(dest, len, value);
644
+    }
639645
 }
640646
 
641647
 #[no_mangle]
@@ -647,7 +653,9 @@ pub extern "C" fn afs_array_add_i32(dest: *mut i32, lhs: *const i32, rhs: *const
647653
     if len == 0 {
648654
         return;
649655
     }
650
-    unsafe { add_i32_impl(dest, lhs, rhs, len); }
656
+    unsafe {
657
+        add_i32_impl(dest, lhs, rhs, len);
658
+    }
651659
 }
652660
 
653661
 #[no_mangle]
@@ -659,7 +667,9 @@ pub extern "C" fn afs_array_add_f32(dest: *mut f32, lhs: *const f32, rhs: *const
659667
     if len == 0 {
660668
         return;
661669
     }
662
-    unsafe { add_f32_impl(dest, lhs, rhs, len); }
670
+    unsafe {
671
+        add_f32_impl(dest, lhs, rhs, len);
672
+    }
663673
 }
664674
 
665675
 #[no_mangle]
@@ -671,7 +681,9 @@ pub extern "C" fn afs_array_add_f64(dest: *mut f64, lhs: *const f64, rhs: *const
671681
     if len == 0 {
672682
         return;
673683
     }
674
-    unsafe { add_f64_impl(dest, lhs, rhs, len); }
684
+    unsafe {
685
+        add_f64_impl(dest, lhs, rhs, len);
686
+    }
675687
 }
676688
 
677689
 #[no_mangle]
@@ -683,7 +695,9 @@ pub extern "C" fn afs_array_sub_i32(dest: *mut i32, lhs: *const i32, rhs: *const
683695
     if len == 0 {
684696
         return;
685697
     }
686
-    unsafe { sub_i32_impl(dest, lhs, rhs, len); }
698
+    unsafe {
699
+        sub_i32_impl(dest, lhs, rhs, len);
700
+    }
687701
 }
688702
 
689703
 #[no_mangle]
@@ -695,7 +709,9 @@ pub extern "C" fn afs_array_sub_f32(dest: *mut f32, lhs: *const f32, rhs: *const
695709
     if len == 0 {
696710
         return;
697711
     }
698
-    unsafe { sub_f32_impl(dest, lhs, rhs, len); }
712
+    unsafe {
713
+        sub_f32_impl(dest, lhs, rhs, len);
714
+    }
699715
 }
700716
 
701717
 #[no_mangle]
@@ -707,7 +723,9 @@ pub extern "C" fn afs_array_sub_f64(dest: *mut f64, lhs: *const f64, rhs: *const
707723
     if len == 0 {
708724
         return;
709725
     }
710
-    unsafe { sub_f64_impl(dest, lhs, rhs, len); }
726
+    unsafe {
727
+        sub_f64_impl(dest, lhs, rhs, len);
728
+    }
711729
 }
712730
 
713731
 #[no_mangle]
@@ -719,7 +737,9 @@ pub extern "C" fn afs_array_mul_i32(dest: *mut i32, lhs: *const i32, rhs: *const
719737
     if len == 0 {
720738
         return;
721739
     }
722
-    unsafe { mul_i32_impl(dest, lhs, rhs, len); }
740
+    unsafe {
741
+        mul_i32_impl(dest, lhs, rhs, len);
742
+    }
723743
 }
724744
 
725745
 #[no_mangle]
@@ -731,7 +751,9 @@ pub extern "C" fn afs_array_mul_f32(dest: *mut f32, lhs: *const f32, rhs: *const
731751
     if len == 0 {
732752
         return;
733753
     }
734
-    unsafe { mul_f32_impl(dest, lhs, rhs, len); }
754
+    unsafe {
755
+        mul_f32_impl(dest, lhs, rhs, len);
756
+    }
735757
 }
736758
 
737759
 #[no_mangle]
@@ -743,7 +765,9 @@ pub extern "C" fn afs_array_mul_f64(dest: *mut f64, lhs: *const f64, rhs: *const
743765
     if len == 0 {
744766
         return;
745767
     }
746
-    unsafe { mul_f64_impl(dest, lhs, rhs, len); }
768
+    unsafe {
769
+        mul_f64_impl(dest, lhs, rhs, len);
770
+    }
747771
 }
748772
 
749773
 #[no_mangle]
@@ -755,7 +779,9 @@ pub extern "C" fn afs_array_add_scalar_i32(dest: *mut i32, src: *const i32, scal
755779
     if len == 0 {
756780
         return;
757781
     }
758
-    unsafe { add_scalar_i32_impl(dest, src, scalar, len); }
782
+    unsafe {
783
+        add_scalar_i32_impl(dest, src, scalar, len);
784
+    }
759785
 }
760786
 
761787
 #[no_mangle]
@@ -767,7 +793,9 @@ pub extern "C" fn afs_array_add_scalar_f32(dest: *mut f32, src: *const f32, scal
767793
     if len == 0 {
768794
         return;
769795
     }
770
-    unsafe { add_scalar_f32_impl(dest, src, scalar, len); }
796
+    unsafe {
797
+        add_scalar_f32_impl(dest, src, scalar, len);
798
+    }
771799
 }
772800
 
773801
 #[no_mangle]
@@ -779,7 +807,9 @@ pub extern "C" fn afs_array_add_scalar_f64(dest: *mut f64, src: *const f64, scal
779807
     if len == 0 {
780808
         return;
781809
     }
782
-    unsafe { add_scalar_f64_impl(dest, src, scalar, len); }
810
+    unsafe {
811
+        add_scalar_f64_impl(dest, src, scalar, len);
812
+    }
783813
 }
784814
 
785815
 #[no_mangle]
@@ -791,7 +821,9 @@ pub extern "C" fn afs_array_sub_scalar_i32(dest: *mut i32, src: *const i32, scal
791821
     if len == 0 {
792822
         return;
793823
     }
794
-    unsafe { sub_scalar_i32_impl(dest, src, scalar, len); }
824
+    unsafe {
825
+        sub_scalar_i32_impl(dest, src, scalar, len);
826
+    }
795827
 }
796828
 
797829
 #[no_mangle]
@@ -803,7 +835,9 @@ pub extern "C" fn afs_array_sub_scalar_f32(dest: *mut f32, src: *const f32, scal
803835
     if len == 0 {
804836
         return;
805837
     }
806
-    unsafe { sub_scalar_f32_impl(dest, src, scalar, len); }
838
+    unsafe {
839
+        sub_scalar_f32_impl(dest, src, scalar, len);
840
+    }
807841
 }
808842
 
809843
 #[no_mangle]
@@ -815,7 +849,9 @@ pub extern "C" fn afs_array_sub_scalar_f64(dest: *mut f64, src: *const f64, scal
815849
     if len == 0 {
816850
         return;
817851
     }
818
-    unsafe { sub_scalar_f64_impl(dest, src, scalar, len); }
852
+    unsafe {
853
+        sub_scalar_f64_impl(dest, src, scalar, len);
854
+    }
819855
 }
820856
 
821857
 #[no_mangle]
@@ -827,7 +863,9 @@ pub extern "C" fn afs_scalar_sub_array_i32(dest: *mut i32, scalar: i32, src: *co
827863
     if len == 0 {
828864
         return;
829865
     }
830
-    unsafe { scalar_sub_i32_impl(dest, scalar, src, len); }
866
+    unsafe {
867
+        scalar_sub_i32_impl(dest, scalar, src, len);
868
+    }
831869
 }
832870
 
833871
 #[no_mangle]
@@ -839,7 +877,9 @@ pub extern "C" fn afs_scalar_sub_array_f32(dest: *mut f32, scalar: f32, src: *co
839877
     if len == 0 {
840878
         return;
841879
     }
842
-    unsafe { scalar_sub_f32_impl(dest, scalar, src, len); }
880
+    unsafe {
881
+        scalar_sub_f32_impl(dest, scalar, src, len);
882
+    }
843883
 }
844884
 
845885
 #[no_mangle]
@@ -851,7 +891,9 @@ pub extern "C" fn afs_scalar_sub_array_f64(dest: *mut f64, scalar: f64, src: *co
851891
     if len == 0 {
852892
         return;
853893
     }
854
-    unsafe { scalar_sub_f64_impl(dest, scalar, src, len); }
894
+    unsafe {
895
+        scalar_sub_f64_impl(dest, scalar, src, len);
896
+    }
855897
 }
856898
 
857899
 #[no_mangle]
@@ -863,7 +905,9 @@ pub extern "C" fn afs_array_mul_scalar_i32(dest: *mut i32, src: *const i32, scal
863905
     if len == 0 {
864906
         return;
865907
     }
866
-    unsafe { mul_scalar_i32_impl(dest, src, scalar, len); }
908
+    unsafe {
909
+        mul_scalar_i32_impl(dest, src, scalar, len);
910
+    }
867911
 }
868912
 
869913
 #[no_mangle]
@@ -875,7 +919,9 @@ pub extern "C" fn afs_array_mul_scalar_f32(dest: *mut f32, src: *const f32, scal
875919
     if len == 0 {
876920
         return;
877921
     }
878
-    unsafe { mul_scalar_f32_impl(dest, src, scalar, len); }
922
+    unsafe {
923
+        mul_scalar_f32_impl(dest, src, scalar, len);
924
+    }
879925
 }
880926
 
881927
 #[no_mangle]
@@ -887,7 +933,9 @@ pub extern "C" fn afs_array_mul_scalar_f64(dest: *mut f64, src: *const f64, scal
887933
     if len == 0 {
888934
         return;
889935
     }
890
-    unsafe { mul_scalar_f64_impl(dest, src, scalar, len); }
936
+    unsafe {
937
+        mul_scalar_f64_impl(dest, src, scalar, len);
938
+    }
891939
 }
892940
 
893941
 // ---- ALLOCATE ----
@@ -909,7 +957,11 @@ pub extern "C" fn afs_allocate_array(
909957
     stat: *mut i32,
910958
 ) {
911959
     if desc.is_null() {
912
-        if !stat.is_null() { unsafe { *stat = 1; } }
960
+        if !stat.is_null() {
961
+            unsafe {
962
+                *stat = 1;
963
+            }
964
+        }
913965
         return;
914966
     }
915967
 
@@ -918,7 +970,9 @@ pub extern "C" fn afs_allocate_array(
918970
     // Check if already allocated.
919971
     if desc.is_allocated() {
920972
         if !stat.is_null() {
921
-            unsafe { *stat = 2; } // already allocated
973
+            unsafe {
974
+                *stat = 2;
975
+            } // already allocated
922976
             return;
923977
         }
924978
         eprintln!("ALLOCATE: array is already allocated");
@@ -943,7 +997,11 @@ pub extern "C" fn afs_allocate_array(
943997
         // Zero-size allocation: valid but produces a null/empty array.
944998
         desc.base_addr = ptr::null_mut();
945999
         desc.flags = DESC_ALLOCATED | DESC_CONTIGUOUS;
946
-        if !stat.is_null() { unsafe { *stat = 0; } }
1000
+        if !stat.is_null() {
1001
+            unsafe {
1002
+                *stat = 0;
1003
+            }
1004
+        }
9471005
         return;
9481006
     }
9491007
 
@@ -951,7 +1009,9 @@ pub extern "C" fn afs_allocate_array(
9511009
     let ptr = unsafe { libc_malloc(bytes as usize) };
9521010
     if ptr.is_null() {
9531011
         if !stat.is_null() {
954
-            unsafe { *stat = 3; } // allocation failed
1012
+            unsafe {
1013
+                *stat = 3;
1014
+            } // allocation failed
9551015
             return;
9561016
         }
9571017
         eprintln!("ALLOCATE: out of memory ({} bytes)", bytes);
@@ -959,24 +1019,36 @@ pub extern "C" fn afs_allocate_array(
9591019
     }
9601020
 
9611021
     // Zero-initialize (Fortran doesn't require this, but it's safer).
962
-    unsafe { ptr::write_bytes(ptr, 0, bytes as usize); }
1022
+    unsafe {
1023
+        ptr::write_bytes(ptr, 0, bytes as usize);
1024
+    }
9631025
 
9641026
     desc.base_addr = ptr;
9651027
     desc.flags = DESC_ALLOCATED | DESC_CONTIGUOUS;
9661028
 
967
-    if !stat.is_null() { unsafe { *stat = 0; } }
1029
+    if !stat.is_null() {
1030
+        unsafe {
1031
+            *stat = 0;
1032
+        }
1033
+    }
9681034
 }
9691035
 
9701036
 /// Simplified allocate for a 1D array with given element count.
9711037
 /// Used by generated code for simple `allocate(a(n))` patterns.
9721038
 #[no_mangle]
973
-pub extern "C" fn afs_allocate_1d(
974
-    desc: *mut ArrayDescriptor,
975
-    elem_size: i64,
976
-    n: i64,
977
-) {
978
-    let dim = DimDescriptor { lower_bound: 1, upper_bound: n, stride: 1 };
979
-    afs_allocate_array(desc, elem_size, 1, &dim as *const DimDescriptor, ptr::null_mut());
1039
+pub extern "C" fn afs_allocate_1d(desc: *mut ArrayDescriptor, elem_size: i64, n: i64) {
1040
+    let dim = DimDescriptor {
1041
+        lower_bound: 1,
1042
+        upper_bound: n,
1043
+        stride: 1,
1044
+    };
1045
+    afs_allocate_array(
1046
+        desc,
1047
+        elem_size,
1048
+        1,
1049
+        &dim as *const DimDescriptor,
1050
+        ptr::null_mut(),
1051
+    );
9801052
 }
9811053
 
9821054
 // ---- DEALLOCATE ----
@@ -985,12 +1057,13 @@ pub extern "C" fn afs_allocate_1d(
9851057
 ///
9861058
 /// Safe to call on an already-deallocated descriptor (no-op with stat=0).
9871059
 #[no_mangle]
988
-pub extern "C" fn afs_deallocate_array(
989
-    desc: *mut ArrayDescriptor,
990
-    stat: *mut i32,
991
-) {
1060
+pub extern "C" fn afs_deallocate_array(desc: *mut ArrayDescriptor, stat: *mut i32) {
9921061
     if desc.is_null() {
993
-        if !stat.is_null() { unsafe { *stat = 1; } }
1062
+        if !stat.is_null() {
1063
+            unsafe {
1064
+                *stat = 1;
1065
+            }
1066
+        }
9941067
         return;
9951068
     }
9961069
 
@@ -999,7 +1072,9 @@ pub extern "C" fn afs_deallocate_array(
9991072
     if !desc.is_allocated() {
10001073
         // Not allocated — not an error with STAT, abort without STAT.
10011074
         if !stat.is_null() {
1002
-            unsafe { *stat = 0; }
1075
+            unsafe {
1076
+                *stat = 0;
1077
+            }
10031078
             return;
10041079
         }
10051080
         // Without STAT, deallocating an unallocated array is an error.
@@ -1009,7 +1084,9 @@ pub extern "C" fn afs_deallocate_array(
10091084
 
10101085
     // Free the data.
10111086
     if !desc.base_addr.is_null() {
1012
-        unsafe { libc_free(desc.base_addr); }
1087
+        unsafe {
1088
+            libc_free(desc.base_addr);
1089
+        }
10131090
     }
10141091
 
10151092
     // Clear the descriptor.
@@ -1017,7 +1094,11 @@ pub extern "C" fn afs_deallocate_array(
10171094
     desc.flags &= !DESC_ALLOCATED;
10181095
     // Leave rank, elem_size, dims intact (they describe the shape for future allocate).
10191096
 
1020
-    if !stat.is_null() { unsafe { *stat = 0; } }
1097
+    if !stat.is_null() {
1098
+        unsafe {
1099
+            *stat = 0;
1100
+        }
1101
+    }
10211102
 }
10221103
 
10231104
 // ---- ALLOCATABLE ASSIGNMENT ----
@@ -1031,22 +1112,24 @@ pub extern "C" fn afs_assign_allocatable(
10311112
     dest: *mut ArrayDescriptor,
10321113
     source: *const ArrayDescriptor,
10331114
 ) {
1034
-    if dest.is_null() || source.is_null() { return; }
1115
+    if dest.is_null() || source.is_null() {
1116
+        return;
1117
+    }
10351118
 
10361119
     let dest = unsafe { &mut *dest };
10371120
     let source = unsafe { &*source };
10381121
 
10391122
     // Check if shapes match.
10401123
     let shapes_match = dest.rank == source.rank && {
1041
-        (0..dest.rank as usize).all(|i| {
1042
-            dest.dims[i].extent() == source.dims[i].extent()
1043
-        })
1124
+        (0..dest.rank as usize).all(|i| dest.dims[i].extent() == source.dims[i].extent())
10441125
     };
10451126
 
10461127
     if !shapes_match || !dest.is_allocated() {
10471128
         // Deallocate dest if allocated.
10481129
         if dest.is_allocated() && !dest.base_addr.is_null() {
1049
-            unsafe { libc_free(dest.base_addr); }
1130
+            unsafe {
1131
+                libc_free(dest.base_addr);
1132
+            }
10501133
             dest.base_addr = ptr::null_mut();
10511134
             dest.flags &= !DESC_ALLOCATED;
10521135
         }
@@ -1087,18 +1170,19 @@ pub extern "C" fn afs_assign_allocatable(
10871170
 /// `to` is deallocated if allocated, then receives `from`'s descriptor.
10881171
 /// `from` is cleared (becomes unallocated).
10891172
 #[no_mangle]
1090
-pub extern "C" fn afs_move_alloc(
1091
-    from: *mut ArrayDescriptor,
1092
-    to: *mut ArrayDescriptor,
1093
-) {
1094
-    if from.is_null() || to.is_null() { return; }
1173
+pub extern "C" fn afs_move_alloc(from: *mut ArrayDescriptor, to: *mut ArrayDescriptor) {
1174
+    if from.is_null() || to.is_null() {
1175
+        return;
1176
+    }
10951177
 
10961178
     let from_desc = unsafe { &mut *from };
10971179
     let to_desc = unsafe { &mut *to };
10981180
 
10991181
     // Deallocate `to` if allocated.
11001182
     if to_desc.is_allocated() && !to_desc.base_addr.is_null() {
1101
-        unsafe { libc_free(to_desc.base_addr); }
1183
+        unsafe {
1184
+            libc_free(to_desc.base_addr);
1185
+        }
11021186
     }
11031187
 
11041188
     // Copy descriptor from `from` to `to`.
@@ -1114,7 +1198,9 @@ pub extern "C" fn afs_move_alloc(
11141198
 /// Check if an array is allocated. Returns 1 (true) or 0 (false).
11151199
 #[no_mangle]
11161200
 pub extern "C" fn afs_allocated(desc: *const ArrayDescriptor) -> i32 {
1117
-    if desc.is_null() { return 0; }
1201
+    if desc.is_null() {
1202
+        return 0;
1203
+    }
11181204
     unsafe { (*desc).is_allocated() as i32 }
11191205
 }
11201206
 
@@ -1140,7 +1226,9 @@ pub extern "C" fn afs_create_section(
11401226
     specs: *const SectionSpec,
11411227
     n_dims: i32,
11421228
 ) {
1143
-    if source.is_null() || result.is_null() || specs.is_null() { return; }
1229
+    if source.is_null() || result.is_null() || specs.is_null() {
1230
+        return;
1231
+    }
11441232
 
11451233
     let source = unsafe { &*source };
11461234
     let result = unsafe { &mut *result };
@@ -1149,7 +1237,7 @@ pub extern "C" fn afs_create_section(
11491237
     result.elem_size = source.elem_size;
11501238
     result.rank = n_dims;
11511239
     result.flags = DESC_CONTIGUOUS; // sections may not be contiguous
1152
-    // Don't set DESC_ALLOCATED — section doesn't own the data.
1240
+                                    // Don't set DESC_ALLOCATED — section doesn't own the data.
11531241
 
11541242
     // Compute base address offset and new dims.
11551243
     let mut byte_offset: i64 = 0;
@@ -1168,7 +1256,8 @@ pub extern "C" fn afs_create_section(
11681256
         let extent = if spec.stride == 0 {
11691257
             1
11701258
         } else if (spec.stride > 0 && spec.start > spec.end)
1171
-            || (spec.stride < 0 && spec.start < spec.end) {
1259
+            || (spec.stride < 0 && spec.start < spec.end)
1260
+        {
11721261
             0 // empty section
11731262
         } else {
11741263
             (spec.end - spec.start) / spec.stride + 1
@@ -1234,8 +1323,16 @@ mod tests {
12341323
     fn allocate_2d() {
12351324
         let mut desc = ArrayDescriptor::zeroed();
12361325
         let dims = [
1237
-            DimDescriptor { lower_bound: 1, upper_bound: 3, stride: 1 },
1238
-            DimDescriptor { lower_bound: 1, upper_bound: 4, stride: 1 },
1326
+            DimDescriptor {
1327
+                lower_bound: 1,
1328
+                upper_bound: 3,
1329
+                stride: 1,
1330
+            },
1331
+            DimDescriptor {
1332
+                lower_bound: 1,
1333
+                upper_bound: 4,
1334
+                stride: 1,
1335
+            },
12391336
         ];
12401337
         afs_allocate_array(&mut desc, 8, 2, dims.as_ptr(), ptr::null_mut());
12411338
         assert!(desc.is_allocated());
@@ -1250,7 +1347,11 @@ mod tests {
12501347
         let mut stat: i32 = -1;
12511348
         afs_allocate_1d(&mut desc, 4, 10);
12521349
         // Allocating again should fail with stat.
1253
-        let dim = DimDescriptor { lower_bound: 1, upper_bound: 10, stride: 1 };
1350
+        let dim = DimDescriptor {
1351
+            lower_bound: 1,
1352
+            upper_bound: 10,
1353
+            stride: 1,
1354
+        };
12541355
         afs_allocate_array(&mut desc, 4, 1, &dim, &mut stat);
12551356
         assert_eq!(stat, 2); // already allocated
12561357
         afs_deallocate_array(&mut desc, ptr::null_mut());
@@ -1333,7 +1434,12 @@ mod tests {
13331434
         let lhs = [1_i32, 2, 3, 4, 5, 6, 7, 8];
13341435
         let rhs = [10_i32, 20, 30, 40, 50, 60, 70, 80];
13351436
         let mut out = [0_i32; 8];
1336
-        afs_array_add_i32(out.as_mut_ptr(), lhs.as_ptr(), rhs.as_ptr(), out.len() as i64);
1437
+        afs_array_add_i32(
1438
+            out.as_mut_ptr(),
1439
+            lhs.as_ptr(),
1440
+            rhs.as_ptr(),
1441
+            out.len() as i64,
1442
+        );
13371443
         assert_eq!(out, [11, 22, 33, 44, 55, 66, 77, 88]);
13381444
     }
13391445
 
@@ -1342,7 +1448,12 @@ mod tests {
13421448
         let lhs = [1.5_f64, 2.5, 3.5, 4.5];
13431449
         let rhs = [10.0_f64, 20.0, 30.0, 40.0];
13441450
         let mut out = [0.0_f64; 4];
1345
-        afs_array_add_f64(out.as_mut_ptr(), lhs.as_ptr(), rhs.as_ptr(), out.len() as i64);
1451
+        afs_array_add_f64(
1452
+            out.as_mut_ptr(),
1453
+            lhs.as_ptr(),
1454
+            rhs.as_ptr(),
1455
+            out.len() as i64,
1456
+        );
13461457
         assert_eq!(out, [11.5, 22.5, 33.5, 44.5]);
13471458
     }
13481459
 
@@ -1351,7 +1462,12 @@ mod tests {
13511462
         let lhs = [11_i32, 22, 33, 44, 55, 66, 77, 88];
13521463
         let rhs = [1_i32, 2, 3, 4, 5, 6, 7, 8];
13531464
         let mut out = [0_i32; 8];
1354
-        afs_array_sub_i32(out.as_mut_ptr(), lhs.as_ptr(), rhs.as_ptr(), out.len() as i64);
1465
+        afs_array_sub_i32(
1466
+            out.as_mut_ptr(),
1467
+            lhs.as_ptr(),
1468
+            rhs.as_ptr(),
1469
+            out.len() as i64,
1470
+        );
13551471
         assert_eq!(out, [10, 20, 30, 40, 50, 60, 70, 80]);
13561472
     }
13571473
 
@@ -1360,7 +1476,12 @@ mod tests {
13601476
         let lhs = [1.0_f32, 2.0, 3.0, 4.0];
13611477
         let rhs = [2.0_f32, 3.0, 4.0, 5.0];
13621478
         let mut out = [0.0_f32; 4];
1363
-        afs_array_mul_f32(out.as_mut_ptr(), lhs.as_ptr(), rhs.as_ptr(), out.len() as i64);
1479
+        afs_array_mul_f32(
1480
+            out.as_mut_ptr(),
1481
+            lhs.as_ptr(),
1482
+            rhs.as_ptr(),
1483
+            out.len() as i64,
1484
+        );
13641485
         assert_eq!(out, [2.0, 6.0, 12.0, 20.0]);
13651486
     }
13661487
 
@@ -1394,43 +1515,63 @@ mod tests {
13941515
 /// SIZE(array) — total number of elements.
13951516
 #[no_mangle]
13961517
 pub extern "C" fn afs_array_size(desc: *const ArrayDescriptor) -> i64 {
1397
-    if desc.is_null() { return 0; }
1518
+    if desc.is_null() {
1519
+        return 0;
1520
+    }
13981521
     unsafe { (*desc).total_elements() }
13991522
 }
14001523
 
14011524
 /// SIZE(array, dim) — number of elements along dimension `dim` (1-based).
14021525
 #[no_mangle]
14031526
 pub extern "C" fn afs_array_size_dim(desc: *const ArrayDescriptor, dim: i32) -> i64 {
1404
-    if desc.is_null() || dim < 1 { return 0; }
1527
+    if desc.is_null() || dim < 1 {
1528
+        return 0;
1529
+    }
14051530
     let d = unsafe { &*desc };
14061531
     let idx = (dim - 1) as usize;
14071532
     if idx < d.rank as usize {
14081533
         d.dims[idx].extent()
1409
-    } else { 0 }
1534
+    } else {
1535
+        0
1536
+    }
14101537
 }
14111538
 
14121539
 /// LBOUND(array, dim) — lower bound along dimension `dim` (1-based).
14131540
 #[no_mangle]
14141541
 pub extern "C" fn afs_array_lbound(desc: *const ArrayDescriptor, dim: i32) -> i64 {
1415
-    if desc.is_null() || dim < 1 { return 1; }
1542
+    if desc.is_null() || dim < 1 {
1543
+        return 1;
1544
+    }
14161545
     let d = unsafe { &*desc };
14171546
     let idx = (dim - 1) as usize;
1418
-    if idx < d.rank as usize { d.dims[idx].lower_bound } else { 1 }
1547
+    if idx < d.rank as usize {
1548
+        d.dims[idx].lower_bound
1549
+    } else {
1550
+        1
1551
+    }
14191552
 }
14201553
 
14211554
 /// UBOUND(array, dim) — upper bound along dimension `dim` (1-based).
14221555
 #[no_mangle]
14231556
 pub extern "C" fn afs_array_ubound(desc: *const ArrayDescriptor, dim: i32) -> i64 {
1424
-    if desc.is_null() || dim < 1 { return 0; }
1557
+    if desc.is_null() || dim < 1 {
1558
+        return 0;
1559
+    }
14251560
     let d = unsafe { &*desc };
14261561
     let idx = (dim - 1) as usize;
1427
-    if idx < d.rank as usize { d.dims[idx].upper_bound } else { 0 }
1562
+    if idx < d.rank as usize {
1563
+        d.dims[idx].upper_bound
1564
+    } else {
1565
+        0
1566
+    }
14281567
 }
14291568
 
14301569
 /// ALLOCATED(array) — check if array is allocated (returns 1 or 0).
14311570
 #[no_mangle]
14321571
 pub extern "C" fn afs_array_allocated(desc: *const ArrayDescriptor) -> i32 {
1433
-    if desc.is_null() { return 0; }
1572
+    if desc.is_null() {
1573
+        return 0;
1574
+    }
14341575
     unsafe { (*desc).is_allocated() as i32 }
14351576
 }
14361577
 
@@ -1438,9 +1579,13 @@ pub extern "C" fn afs_array_allocated(desc: *const ArrayDescriptor) -> i32 {
14381579
 /// Respects strides for non-contiguous sections.
14391580
 #[no_mangle]
14401581
 pub extern "C" fn afs_array_sum_real8(desc: *const ArrayDescriptor) -> f64 {
1441
-    if desc.is_null() { return 0.0; }
1582
+    if desc.is_null() {
1583
+        return 0.0;
1584
+    }
14421585
     let d = unsafe { &*desc };
1443
-    if d.base_addr.is_null() { return 0.0; }
1586
+    if d.base_addr.is_null() {
1587
+        return 0.0;
1588
+    }
14441589
     let n = d.total_elements() as usize;
14451590
     let stride = d.dims[0].stride.max(1) as usize;
14461591
     let ptr = d.base_addr as *const f64;
@@ -1455,9 +1600,13 @@ pub extern "C" fn afs_array_sum_real8(desc: *const ArrayDescriptor) -> f64 {
14551600
 /// Respects strides for non-contiguous sections.
14561601
 #[no_mangle]
14571602
 pub extern "C" fn afs_array_sum_int(desc: *const ArrayDescriptor) -> i64 {
1458
-    if desc.is_null() { return 0; }
1603
+    if desc.is_null() {
1604
+        return 0;
1605
+    }
14591606
     let d = unsafe { &*desc };
1460
-    if d.base_addr.is_null() { return 0; }
1607
+    if d.base_addr.is_null() {
1608
+        return 0;
1609
+    }
14611610
     let n = d.total_elements() as usize;
14621611
     let stride = d.dims[0].stride.max(1) as usize;
14631612
     let ptr = d.base_addr as *const i32;
@@ -1471,9 +1620,13 @@ pub extern "C" fn afs_array_sum_int(desc: *const ArrayDescriptor) -> i64 {
14711620
 /// PRODUCT(array) — product of all elements (real(8) version).
14721621
 #[no_mangle]
14731622
 pub extern "C" fn afs_array_product_real8(desc: *const ArrayDescriptor) -> f64 {
1474
-    if desc.is_null() { return 1.0; }
1623
+    if desc.is_null() {
1624
+        return 1.0;
1625
+    }
14751626
     let d = unsafe { &*desc };
1476
-    if d.base_addr.is_null() { return 1.0; }
1627
+    if d.base_addr.is_null() {
1628
+        return 1.0;
1629
+    }
14771630
     let n = d.total_elements() as usize;
14781631
     let stride = d.dims[0].stride.max(1) as usize;
14791632
     let ptr = d.base_addr as *const f64;
@@ -1487,11 +1640,17 @@ pub extern "C" fn afs_array_product_real8(desc: *const ArrayDescriptor) -> f64 {
14871640
 /// PRODUCT(array) — product of all elements (integer(4) version).
14881641
 #[no_mangle]
14891642
 pub extern "C" fn afs_array_product_int(desc: *const ArrayDescriptor) -> i64 {
1490
-    if desc.is_null() { return 1; }
1643
+    if desc.is_null() {
1644
+        return 1;
1645
+    }
14911646
     let d = unsafe { &*desc };
1492
-    if d.base_addr.is_null() { return 1; }
1647
+    if d.base_addr.is_null() {
1648
+        return 1;
1649
+    }
14931650
     let n = d.total_elements() as usize;
1494
-    if n == 0 { return 1; }
1651
+    if n == 0 {
1652
+        return 1;
1653
+    }
14951654
     let stride = d.dims[0].stride.max(1) as usize;
14961655
     let ptr = d.base_addr as *const i32;
14971656
     let mut prod: i64 = 1;
@@ -1504,17 +1663,25 @@ pub extern "C" fn afs_array_product_int(desc: *const ArrayDescriptor) -> i64 {
15041663
 /// MAXVAL(array) — maximum element (real(8) version). Respects strides.
15051664
 #[no_mangle]
15061665
 pub extern "C" fn afs_array_maxval_real8(desc: *const ArrayDescriptor) -> f64 {
1507
-    if desc.is_null() { return f64::NEG_INFINITY; }
1666
+    if desc.is_null() {
1667
+        return f64::NEG_INFINITY;
1668
+    }
15081669
     let d = unsafe { &*desc };
1509
-    if d.base_addr.is_null() { return f64::NEG_INFINITY; }
1670
+    if d.base_addr.is_null() {
1671
+        return f64::NEG_INFINITY;
1672
+    }
15101673
     let n = d.total_elements() as usize;
1511
-    if n == 0 { return f64::NEG_INFINITY; }
1674
+    if n == 0 {
1675
+        return f64::NEG_INFINITY;
1676
+    }
15121677
     let stride = d.dims[0].stride.max(1) as usize;
15131678
     let ptr = d.base_addr as *const f64;
15141679
     let mut max = unsafe { *ptr };
15151680
     for i in 1..n {
15161681
         let v = unsafe { *ptr.add(i * stride) };
1517
-        if v > max { max = v; }
1682
+        if v > max {
1683
+            max = v;
1684
+        }
15181685
     }
15191686
     max
15201687
 }
@@ -1522,17 +1689,25 @@ pub extern "C" fn afs_array_maxval_real8(desc: *const ArrayDescriptor) -> f64 {
15221689
 /// MINVAL(array) — minimum element (real(8) version). Respects strides.
15231690
 #[no_mangle]
15241691
 pub extern "C" fn afs_array_minval_real8(desc: *const ArrayDescriptor) -> f64 {
1525
-    if desc.is_null() { return f64::INFINITY; }
1692
+    if desc.is_null() {
1693
+        return f64::INFINITY;
1694
+    }
15261695
     let d = unsafe { &*desc };
1527
-    if d.base_addr.is_null() { return f64::INFINITY; }
1696
+    if d.base_addr.is_null() {
1697
+        return f64::INFINITY;
1698
+    }
15281699
     let n = d.total_elements() as usize;
1529
-    if n == 0 { return f64::INFINITY; }
1700
+    if n == 0 {
1701
+        return f64::INFINITY;
1702
+    }
15301703
     let stride = d.dims[0].stride.max(1) as usize;
15311704
     let ptr = d.base_addr as *const f64;
15321705
     let mut min = unsafe { *ptr };
15331706
     for i in 1..n {
15341707
         let v = unsafe { *ptr.add(i * stride) };
1535
-        if v < min { min = v; }
1708
+        if v < min {
1709
+            min = v;
1710
+        }
15361711
     }
15371712
     min
15381713
 }
@@ -1540,17 +1715,25 @@ pub extern "C" fn afs_array_minval_real8(desc: *const ArrayDescriptor) -> f64 {
15401715
 /// MAXVAL(array) — maximum element (integer(4) version). Respects strides.
15411716
 #[no_mangle]
15421717
 pub extern "C" fn afs_array_maxval_int(desc: *const ArrayDescriptor) -> i32 {
1543
-    if desc.is_null() { return i32::MIN; }
1718
+    if desc.is_null() {
1719
+        return i32::MIN;
1720
+    }
15441721
     let d = unsafe { &*desc };
1545
-    if d.base_addr.is_null() { return i32::MIN; }
1722
+    if d.base_addr.is_null() {
1723
+        return i32::MIN;
1724
+    }
15461725
     let n = d.total_elements() as usize;
1547
-    if n == 0 { return i32::MIN; }
1726
+    if n == 0 {
1727
+        return i32::MIN;
1728
+    }
15481729
     let stride = d.dims[0].stride.max(1) as usize;
15491730
     let ptr = d.base_addr as *const i32;
15501731
     let mut max = unsafe { *ptr };
15511732
     for i in 1..n {
15521733
         let v = unsafe { *ptr.add(i * stride) };
1553
-        if v > max { max = v; }
1734
+        if v > max {
1735
+            max = v;
1736
+        }
15541737
     }
15551738
     max
15561739
 }
@@ -1558,17 +1741,25 @@ pub extern "C" fn afs_array_maxval_int(desc: *const ArrayDescriptor) -> i32 {
15581741
 /// MINVAL(array) — minimum element (integer(4) version). Respects strides.
15591742
 #[no_mangle]
15601743
 pub extern "C" fn afs_array_minval_int(desc: *const ArrayDescriptor) -> i32 {
1561
-    if desc.is_null() { return i32::MAX; }
1744
+    if desc.is_null() {
1745
+        return i32::MAX;
1746
+    }
15621747
     let d = unsafe { &*desc };
1563
-    if d.base_addr.is_null() { return i32::MAX; }
1748
+    if d.base_addr.is_null() {
1749
+        return i32::MAX;
1750
+    }
15641751
     let n = d.total_elements() as usize;
1565
-    if n == 0 { return i32::MAX; }
1752
+    if n == 0 {
1753
+        return i32::MAX;
1754
+    }
15661755
     let stride = d.dims[0].stride.max(1) as usize;
15671756
     let ptr = d.base_addr as *const i32;
15681757
     let mut min = unsafe { *ptr };
15691758
     for i in 1..n {
15701759
         let v = unsafe { *ptr.add(i * stride) };
1571
-        if v < min { min = v; }
1760
+        if v < min {
1761
+            min = v;
1762
+        }
15721763
     }
15731764
     min
15741765
 }
@@ -1580,9 +1771,13 @@ pub extern "C" fn afs_transpose_real8(
15801771
     source: *const ArrayDescriptor,
15811772
     result: *mut ArrayDescriptor,
15821773
 ) {
1583
-    if source.is_null() || result.is_null() { return; }
1774
+    if source.is_null() || result.is_null() {
1775
+        return;
1776
+    }
15841777
     let src = unsafe { &*source };
1585
-    if src.rank < 2 || src.base_addr.is_null() { return; }
1778
+    if src.rank < 2 || src.base_addr.is_null() {
1779
+        return;
1780
+    }
15861781
 
15871782
     let m = src.dims[0].extent() as usize;
15881783
     let n = src.dims[1].extent() as usize;
@@ -1592,13 +1787,23 @@ pub extern "C" fn afs_transpose_real8(
15921787
     afs_allocate_1d(result, 8, (n * m) as i64);
15931788
     let res = unsafe { &mut *result };
15941789
     res.rank = 2;
1595
-    res.dims[0] = DimDescriptor { lower_bound: 1, upper_bound: n as i64, stride: 1 };
1596
-    res.dims[1] = DimDescriptor { lower_bound: 1, upper_bound: m as i64, stride: 1 };
1790
+    res.dims[0] = DimDescriptor {
1791
+        lower_bound: 1,
1792
+        upper_bound: n as i64,
1793
+        stride: 1,
1794
+    };
1795
+    res.dims[1] = DimDescriptor {
1796
+        lower_bound: 1,
1797
+        upper_bound: m as i64,
1798
+        stride: 1,
1799
+    };
15971800
     let rp = res.base_addr as *mut f64;
15981801
 
15991802
     for i in 0..m {
16001803
         for j in 0..n {
1601
-            unsafe { *rp.add(j * m + i) = *sp.add(i * n + j); }
1804
+            unsafe {
1805
+                *rp.add(j * m + i) = *sp.add(i * n + j);
1806
+            }
16021807
         }
16031808
     }
16041809
 }
@@ -1611,14 +1816,26 @@ pub extern "C" fn afs_matmul_real8(
16111816
     b: *const ArrayDescriptor,
16121817
     result: *mut ArrayDescriptor,
16131818
 ) {
1614
-    if a.is_null() || b.is_null() || result.is_null() { return; }
1819
+    if a.is_null() || b.is_null() || result.is_null() {
1820
+        return;
1821
+    }
16151822
     let da = unsafe { &*a };
16161823
     let db = unsafe { &*b };
1617
-    if da.base_addr.is_null() || db.base_addr.is_null() { return; }
1824
+    if da.base_addr.is_null() || db.base_addr.is_null() {
1825
+        return;
1826
+    }
16181827
 
16191828
     let m = da.dims[0].extent() as usize;
1620
-    let k = if da.rank >= 2 { da.dims[1].extent() as usize } else { 1 };
1621
-    let n = if db.rank >= 2 { db.dims[1].extent() as usize } else { db.dims[0].extent() as usize };
1829
+    let k = if da.rank >= 2 {
1830
+        da.dims[1].extent() as usize
1831
+    } else {
1832
+        1
1833
+    };
1834
+    let n = if db.rank >= 2 {
1835
+        db.dims[1].extent() as usize
1836
+    } else {
1837
+        db.dims[0].extent() as usize
1838
+    };
16221839
 
16231840
     // For vector * matrix or matrix * vector, adjust dimensions.
16241841
     let ap = da.base_addr as *const f64;
@@ -1628,8 +1845,16 @@ pub extern "C" fn afs_matmul_real8(
16281845
     afs_allocate_1d(result, 8, (m * n) as i64);
16291846
     let res = unsafe { &mut *result };
16301847
     res.rank = 2;
1631
-    res.dims[0] = DimDescriptor { lower_bound: 1, upper_bound: m as i64, stride: 1 };
1632
-    res.dims[1] = DimDescriptor { lower_bound: 1, upper_bound: n as i64, stride: 1 };
1848
+    res.dims[0] = DimDescriptor {
1849
+        lower_bound: 1,
1850
+        upper_bound: m as i64,
1851
+        stride: 1,
1852
+    };
1853
+    res.dims[1] = DimDescriptor {
1854
+        lower_bound: 1,
1855
+        upper_bound: n as i64,
1856
+        stride: 1,
1857
+    };
16331858
     let rp = res.base_addr as *mut f64;
16341859
 
16351860
     // Triple loop: C(i,j) = sum_l A(i,l) * B(l,j)
@@ -1641,7 +1866,9 @@ pub extern "C" fn afs_matmul_real8(
16411866
                 let b_val = unsafe { *bp.add(l * n + j) };
16421867
                 sum += a_val * b_val;
16431868
             }
1644
-            unsafe { *rp.add(i * n + j) = sum; }
1869
+            unsafe {
1870
+                *rp.add(i * n + j) = sum;
1871
+            }
16451872
         }
16461873
     }
16471874
 }
@@ -1653,14 +1880,26 @@ pub extern "C" fn afs_matmul_int(
16531880
     b: *const ArrayDescriptor,
16541881
     result: *mut ArrayDescriptor,
16551882
 ) {
1656
-    if a.is_null() || b.is_null() || result.is_null() { return; }
1883
+    if a.is_null() || b.is_null() || result.is_null() {
1884
+        return;
1885
+    }
16571886
     let da = unsafe { &*a };
16581887
     let db = unsafe { &*b };
1659
-    if da.base_addr.is_null() || db.base_addr.is_null() { return; }
1888
+    if da.base_addr.is_null() || db.base_addr.is_null() {
1889
+        return;
1890
+    }
16601891
 
16611892
     let m = da.dims[0].extent() as usize;
1662
-    let k = if da.rank >= 2 { da.dims[1].extent() as usize } else { 1 };
1663
-    let n = if db.rank >= 2 { db.dims[1].extent() as usize } else { db.dims[0].extent() as usize };
1893
+    let k = if da.rank >= 2 {
1894
+        da.dims[1].extent() as usize
1895
+    } else {
1896
+        1
1897
+    };
1898
+    let n = if db.rank >= 2 {
1899
+        db.dims[1].extent() as usize
1900
+    } else {
1901
+        db.dims[0].extent() as usize
1902
+    };
16641903
 
16651904
     let ap = da.base_addr as *const i32;
16661905
     let bp = db.base_addr as *const i32;
@@ -1668,8 +1907,16 @@ pub extern "C" fn afs_matmul_int(
16681907
     afs_allocate_1d(result, 4, (m * n) as i64);
16691908
     let res = unsafe { &mut *result };
16701909
     res.rank = 2;
1671
-    res.dims[0] = DimDescriptor { lower_bound: 1, upper_bound: m as i64, stride: 1 };
1672
-    res.dims[1] = DimDescriptor { lower_bound: 1, upper_bound: n as i64, stride: 1 };
1910
+    res.dims[0] = DimDescriptor {
1911
+        lower_bound: 1,
1912
+        upper_bound: m as i64,
1913
+        stride: 1,
1914
+    };
1915
+    res.dims[1] = DimDescriptor {
1916
+        lower_bound: 1,
1917
+        upper_bound: n as i64,
1918
+        stride: 1,
1919
+    };
16731920
     let rp = res.base_addr as *mut i32;
16741921
 
16751922
     for i in 0..m {
@@ -1680,20 +1927,23 @@ pub extern "C" fn afs_matmul_int(
16801927
                 let b_val = unsafe { *bp.add(l * n + j) as i64 };
16811928
                 sum += a_val * b_val;
16821929
             }
1683
-            unsafe { *rp.add(i * n + j) = sum as i32; }
1930
+            unsafe {
1931
+                *rp.add(i * n + j) = sum as i32;
1932
+            }
16841933
         }
16851934
     }
16861935
 }
16871936
 
16881937
 /// TRANSPOSE(source, result) — matrix transpose (integer(4) version).
16891938
 #[no_mangle]
1690
-pub extern "C" fn afs_transpose_int(
1691
-    source: *const ArrayDescriptor,
1692
-    result: *mut ArrayDescriptor,
1693
-) {
1694
-    if source.is_null() || result.is_null() { return; }
1939
+pub extern "C" fn afs_transpose_int(source: *const ArrayDescriptor, result: *mut ArrayDescriptor) {
1940
+    if source.is_null() || result.is_null() {
1941
+        return;
1942
+    }
16951943
     let src = unsafe { &*source };
1696
-    if src.rank < 2 || src.base_addr.is_null() { return; }
1944
+    if src.rank < 2 || src.base_addr.is_null() {
1945
+        return;
1946
+    }
16971947
 
16981948
     let m = src.dims[0].extent() as usize;
16991949
     let n = src.dims[1].extent() as usize;
@@ -1702,13 +1952,23 @@ pub extern "C" fn afs_transpose_int(
17021952
     afs_allocate_1d(result, 4, (n * m) as i64);
17031953
     let res = unsafe { &mut *result };
17041954
     res.rank = 2;
1705
-    res.dims[0] = DimDescriptor { lower_bound: 1, upper_bound: n as i64, stride: 1 };
1706
-    res.dims[1] = DimDescriptor { lower_bound: 1, upper_bound: m as i64, stride: 1 };
1955
+    res.dims[0] = DimDescriptor {
1956
+        lower_bound: 1,
1957
+        upper_bound: n as i64,
1958
+        stride: 1,
1959
+    };
1960
+    res.dims[1] = DimDescriptor {
1961
+        lower_bound: 1,
1962
+        upper_bound: m as i64,
1963
+        stride: 1,
1964
+    };
17071965
     let rp = res.base_addr as *mut i32;
17081966
 
17091967
     for i in 0..m {
17101968
         for j in 0..n {
1711
-            unsafe { *rp.add(j * m + i) = *sp.add(i * n + j); }
1969
+            unsafe {
1970
+                *rp.add(j * m + i) = *sp.add(i * n + j);
1971
+            }
17121972
         }
17131973
     }
17141974
 }
@@ -1720,10 +1980,14 @@ pub extern "C" fn afs_dot_product_real8(
17201980
     a: *const ArrayDescriptor,
17211981
     b: *const ArrayDescriptor,
17221982
 ) -> f64 {
1723
-    if a.is_null() || b.is_null() { return 0.0; }
1983
+    if a.is_null() || b.is_null() {
1984
+        return 0.0;
1985
+    }
17241986
     let da = unsafe { &*a };
17251987
     let db = unsafe { &*b };
1726
-    if da.base_addr.is_null() || db.base_addr.is_null() { return 0.0; }
1988
+    if da.base_addr.is_null() || db.base_addr.is_null() {
1989
+        return 0.0;
1990
+    }
17271991
     let n = da.dims[0].extent().min(db.dims[0].extent()) as usize;
17281992
     let stride_a = da.dims[0].stride.max(1) as usize;
17291993
     let stride_b = db.dims[0].stride.max(1) as usize;
@@ -1742,10 +2006,14 @@ pub extern "C" fn afs_dot_product_real4(
17422006
     a: *const ArrayDescriptor,
17432007
     b: *const ArrayDescriptor,
17442008
 ) -> f32 {
1745
-    if a.is_null() || b.is_null() { return 0.0; }
2009
+    if a.is_null() || b.is_null() {
2010
+        return 0.0;
2011
+    }
17462012
     let da = unsafe { &*a };
17472013
     let db = unsafe { &*b };
1748
-    if da.base_addr.is_null() || db.base_addr.is_null() { return 0.0; }
2014
+    if da.base_addr.is_null() || db.base_addr.is_null() {
2015
+        return 0.0;
2016
+    }
17492017
     let n = da.dims[0].extent().min(db.dims[0].extent()) as usize;
17502018
     let stride_a = da.dims[0].stride.max(1) as usize;
17512019
     let stride_b = db.dims[0].stride.max(1) as usize;
@@ -1760,14 +2028,15 @@ pub extern "C" fn afs_dot_product_real4(
17602028
 
17612029
 /// DOT_PRODUCT(a, b) — vector dot product (integer(4) version).
17622030
 #[no_mangle]
1763
-pub extern "C" fn afs_dot_product_int(
1764
-    a: *const ArrayDescriptor,
1765
-    b: *const ArrayDescriptor,
1766
-) -> i64 {
1767
-    if a.is_null() || b.is_null() { return 0; }
2031
+pub extern "C" fn afs_dot_product_int(a: *const ArrayDescriptor, b: *const ArrayDescriptor) -> i64 {
2032
+    if a.is_null() || b.is_null() {
2033
+        return 0;
2034
+    }
17682035
     let da = unsafe { &*a };
17692036
     let db = unsafe { &*b };
1770
-    if da.base_addr.is_null() || db.base_addr.is_null() { return 0; }
2037
+    if da.base_addr.is_null() || db.base_addr.is_null() {
2038
+        return 0;
2039
+    }
17712040
     let n = da.dims[0].extent().min(db.dims[0].extent()) as usize;
17722041
     let stride_a = da.dims[0].stride.max(1) as usize;
17732042
     let stride_b = db.dims[0].stride.max(1) as usize;
runtime/src/descriptor.rsmodified
36 lines changed — click to load
@@ -221,13 +221,25 @@ mod tests {
221221
 
222222
     #[test]
223223
     fn dim_extent() {
224
-        let dim = DimDescriptor { lower_bound: 1, upper_bound: 10, stride: 1 };
224
+        let dim = DimDescriptor {
225
+            lower_bound: 1,
226
+            upper_bound: 10,
227
+            stride: 1,
228
+        };
225229
         assert_eq!(dim.extent(), 10);
226230
 
227
-        let dim2 = DimDescriptor { lower_bound: 1, upper_bound: 10, stride: 2 };
231
+        let dim2 = DimDescriptor {
232
+            lower_bound: 1,
233
+            upper_bound: 10,
234
+            stride: 2,
235
+        };
228236
         assert_eq!(dim2.extent(), 5);
229237
 
230
-        let dim3 = DimDescriptor { lower_bound: 5, upper_bound: 3, stride: 1 };
238
+        let dim3 = DimDescriptor {
239
+            lower_bound: 5,
240
+            upper_bound: 3,
241
+            stride: 1,
242
+        };
231243
         assert_eq!(dim3.extent(), 0); // empty
232244
     }
233245
 
@@ -256,7 +268,7 @@ mod tests {
256268
         let mut d = ArrayDescriptor::zeroed();
257269
         d.elem_size = 8; // f64
258270
         d.set_bounds(&[(1, 3), (1, 4)]); // 3x4 matrix
259
-        // Column-major: a(1,1)=0, a(2,1)=8, a(3,1)=16, a(1,2)=24
271
+                                         // Column-major: a(1,1)=0, a(2,1)=8, a(3,1)=16, a(1,2)=24
260272
         assert_eq!(d.element_offset(&[1, 1]), 0);
261273
         assert_eq!(d.element_offset(&[2, 1]), 8);
262274
         assert_eq!(d.element_offset(&[3, 1]), 16);
runtime/src/format.rsmodified
888 lines changed — click to load
@@ -5,33 +5,64 @@
55
 //! Fortran standard set including repeat counts, group repeat,
66
 //! unlimited repeat, scale factors, and all data/control descriptors.
77
 
8
-
98
 /// A parsed format descriptor.
109
 #[derive(Debug, Clone)]
1110
 pub enum FormatDesc {
1211
     // ---- Data edit descriptors ----
1312
     /// I: integer. Iw or Iw.m (w=width, m=minimum digits).
14
-    IntegerI { width: usize, min_digits: Option<usize> },
13
+    IntegerI {
14
+        width: usize,
15
+        min_digits: Option<usize>,
16
+    },
1517
     /// B: binary integer. Bw or Bw.m.
16
-    IntegerB { width: usize, min_digits: Option<usize> },
18
+    IntegerB {
19
+        width: usize,
20
+        min_digits: Option<usize>,
21
+    },
1722
     /// O: octal integer. Ow or Ow.m.
18
-    IntegerO { width: usize, min_digits: Option<usize> },
23
+    IntegerO {
24
+        width: usize,
25
+        min_digits: Option<usize>,
26
+    },
1927
     /// Z: hexadecimal integer. Zw or Zw.m.
20
-    IntegerZ { width: usize, min_digits: Option<usize> },
28
+    IntegerZ {
29
+        width: usize,
30
+        min_digits: Option<usize>,
31
+    },
2132
     /// F: fixed-point real. Fw.d.
2233
     RealF { width: usize, decimals: usize },
2334
     /// E: exponential real. Ew.d or Ew.dEe.
24
-    RealE { width: usize, decimals: usize, exp_width: Option<usize> },
35
+    RealE {
36
+        width: usize,
37
+        decimals: usize,
38
+        exp_width: Option<usize>,
39
+    },
2540
     /// EN: engineering notation. ENw.d or ENw.dEe.
26
-    RealEN { width: usize, decimals: usize, exp_width: Option<usize> },
41
+    RealEN {
42
+        width: usize,
43
+        decimals: usize,
44
+        exp_width: Option<usize>,
45
+    },
2746
     /// ES: scientific notation (1.0-9.999 mantissa). ESw.d or ESw.dEe.
28
-    RealES { width: usize, decimals: usize, exp_width: Option<usize> },
47
+    RealES {
48
+        width: usize,
49
+        decimals: usize,
50
+        exp_width: Option<usize>,
51
+    },
2952
     /// EX: hexadecimal-significand real. EXw.d or EXw.dEe. (F2018)
30
-    RealEX { width: usize, decimals: usize, exp_width: Option<usize> },
53
+    RealEX {
54
+        width: usize,
55
+        decimals: usize,
56
+        exp_width: Option<usize>,
57
+    },
3158
     /// D: double-precision exponential. Dw.d (same as Ew.d with D exponent letter).
3259
     RealD { width: usize, decimals: usize },
3360
     /// G: generalized real. Gw.d or Gw.dEe. Chooses F or E format automatically.
34
-    RealG { width: usize, decimals: usize, exp_width: Option<usize> },
61
+    RealG {
62
+        width: usize,
63
+        decimals: usize,
64
+        exp_width: Option<usize>,
65
+    },
3566
     /// L: logical. Lw.
3667
     Logical { width: usize },
3768
     /// A: character. A or Aw.
@@ -69,7 +100,10 @@ pub enum FormatDesc {
69100
 
70101
     // ---- Grouping ----
71102
     /// Repeated group: n(...).
72
-    Group { repeat: usize, descriptors: Vec<FormatDesc> },
103
+    Group {
104
+        repeat: usize,
105
+        descriptors: Vec<FormatDesc>,
106
+    },
73107
     /// Unlimited repeat: *(...).
74108
     UnlimitedRepeat { descriptors: Vec<FormatDesc> },
75109
 }
@@ -94,18 +128,18 @@ pub enum BlankInterpretation {
94128
 
95129
 #[derive(Debug, Clone, Copy)]
96130
 pub enum RoundMode {
97
-    Up,          // RU
98
-    Down,        // RD
99
-    Zero,        // RZ
100
-    Nearest,     // RN
101
-    Compatible,  // RC
131
+    Up,               // RU
132
+    Down,             // RD
133
+    Zero,             // RZ
134
+    Nearest,          // RN
135
+    Compatible,       // RC
102136
     ProcessorDefined, // RP
103137
 }
104138
 
105139
 #[derive(Debug, Clone, Copy)]
106140
 pub enum DecimalSep {
107
-    Comma,  // DC
108
-    Point,  // DP
141
+    Comma, // DC
142
+    Point, // DP
109143
 }
110144
 
111145
 /// Parse a Fortran format string (the part inside parentheses) into descriptors.
@@ -113,7 +147,7 @@ pub fn parse_format(fmt: &str) -> Vec<FormatDesc> {
113147
     let trimmed = fmt.trim();
114148
     // Strip outer parens if present.
115149
     let inner = if trimmed.starts_with('(') && trimmed.ends_with(')') {
116
-        &trimmed[1..trimmed.len()-1]
150
+        &trimmed[1..trimmed.len() - 1]
117151
     } else {
118152
         trimmed
119153
     };
@@ -126,7 +160,9 @@ fn parse_format_list(input: &str) -> Vec<FormatDesc> {
126160
 
127161
     while chars.peek().is_some() {
128162
         skip_spaces(&mut chars);
129
-        if chars.peek().is_none() { break; }
163
+        if chars.peek().is_none() {
164
+            break;
165
+        }
130166
 
131167
         // Check for comma separator.
132168
         if chars.peek() == Some(&',') {
@@ -146,7 +182,9 @@ fn parse_format_list(input: &str) -> Vec<FormatDesc> {
146182
         let repeat = parse_number(&mut chars);
147183
 
148184
         skip_spaces(&mut chars);
149
-        if chars.peek().is_none() { break; }
185
+        if chars.peek().is_none() {
186
+            break;
187
+        }
150188
 
151189
         let c = chars.peek().copied().unwrap_or(' ');
152190
 
@@ -161,7 +199,10 @@ fn parse_format_list(input: &str) -> Vec<FormatDesc> {
161199
                     // *(...) unlimited repeat — not representable with 0.
162200
                     result.push(FormatDesc::UnlimitedRepeat { descriptors });
163201
                 } else {
164
-                    result.push(FormatDesc::Group { repeat: n, descriptors });
202
+                    result.push(FormatDesc::Group {
203
+                        repeat: n,
204
+                        descriptors,
205
+                    });
165206
                 }
166207
             }
167208
 
@@ -203,9 +244,14 @@ fn parse_format_list(input: &str) -> Vec<FormatDesc> {
203244
                 let desc = parse_edit_descriptor(&mut chars, repeat, negative);
204245
                 if let Some(d) = desc {
205246
                     if let Some(n) = repeat {
206
-                        if n > 1 && !matches!(d, FormatDesc::Skip { .. } | FormatDesc::ScaleFactor(_)) {
247
+                        if n > 1
248
+                            && !matches!(d, FormatDesc::Skip { .. } | FormatDesc::ScaleFactor(_))
249
+                        {
207250
                             // Repeat count on a data descriptor: wrap in a group.
208
-                            result.push(FormatDesc::Group { repeat: n, descriptors: vec![d] });
251
+                            result.push(FormatDesc::Group {
252
+                                repeat: n,
253
+                                descriptors: vec![d],
254
+                            });
209255
                         } else {
210256
                             result.push(d);
211257
                         }
@@ -230,47 +276,122 @@ fn parse_edit_descriptor(
230276
     match letter {
231277
         'I' => {
232278
             let w = parse_number(chars).unwrap_or(0);
233
-            let m = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars) } else { None };
234
-            Some(FormatDesc::IntegerI { width: w, min_digits: m })
279
+            let m = if chars.peek() == Some(&'.') {
280
+                chars.next();
281
+                parse_number(chars)
282
+            } else {
283
+                None
284
+            };
285
+            Some(FormatDesc::IntegerI {
286
+                width: w,
287
+                min_digits: m,
288
+            })
235289
         }
236
-        'B' if chars.peek().map(|c| c.is_ascii_digit() || *c == '\'').unwrap_or(false) => {
290
+        'B' if chars
291
+            .peek()
292
+            .map(|c| c.is_ascii_digit() || *c == '\'')
293
+            .unwrap_or(false) =>
294
+        {
237295
             // B followed by digit → binary integer format.
238296
             // B followed by quote → BOZ literal (not handled here).
239297
             let w = parse_number(chars).unwrap_or(0);
240
-            let m = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars) } else { None };
241
-            Some(FormatDesc::IntegerB { width: w, min_digits: m })
298
+            let m = if chars.peek() == Some(&'.') {
299
+                chars.next();
300
+                parse_number(chars)
301
+            } else {
302
+                None
303
+            };
304
+            Some(FormatDesc::IntegerB {
305
+                width: w,
306
+                min_digits: m,
307
+            })
242308
         }
243309
         'O' => {
244310
             let w = parse_number(chars).unwrap_or(0);
245
-            let m = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars) } else { None };
246
-            Some(FormatDesc::IntegerO { width: w, min_digits: m })
311
+            let m = if chars.peek() == Some(&'.') {
312
+                chars.next();
313
+                parse_number(chars)
314
+            } else {
315
+                None
316
+            };
317
+            Some(FormatDesc::IntegerO {
318
+                width: w,
319
+                min_digits: m,
320
+            })
247321
         }
248322
         'Z' => {
249323
             let w = parse_number(chars).unwrap_or(0);
250
-            let m = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars) } else { None };
251
-            Some(FormatDesc::IntegerZ { width: w, min_digits: m })
324
+            let m = if chars.peek() == Some(&'.') {
325
+                chars.next();
326
+                parse_number(chars)
327
+            } else {
328
+                None
329
+            };
330
+            Some(FormatDesc::IntegerZ {
331
+                width: w,
332
+                min_digits: m,
333
+            })
252334
         }
253335
         'F' => {
254336
             let w = parse_number(chars).unwrap_or(0);
255
-            let d = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars).unwrap_or(0) } else { 0 };
256
-            Some(FormatDesc::RealF { width: w, decimals: d })
337
+            let d = if chars.peek() == Some(&'.') {
338
+                chars.next();
339
+                parse_number(chars).unwrap_or(0)
340
+            } else {
341
+                0
342
+            };
343
+            Some(FormatDesc::RealF {
344
+                width: w,
345
+                decimals: d,
346
+            })
257347
         }
258348
         'E' => {
259349
             // Check for EN, ES, EX.
260350
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
261351
             match next {
262
-                'N' => { chars.next(); parse_real_desc(chars, |w, d, e| FormatDesc::RealEN { width: w, decimals: d, exp_width: e }) }
263
-                'S' => { chars.next(); parse_real_desc(chars, |w, d, e| FormatDesc::RealES { width: w, decimals: d, exp_width: e }) }
264
-                'X' => { chars.next(); parse_real_desc(chars, |w, d, e| FormatDesc::RealEX { width: w, decimals: d, exp_width: e }) }
265
-                _ => parse_real_desc(chars, |w, d, e| FormatDesc::RealE { width: w, decimals: d, exp_width: e }),
352
+                'N' => {
353
+                    chars.next();
354
+                    parse_real_desc(chars, |w, d, e| FormatDesc::RealEN {
355
+                        width: w,
356
+                        decimals: d,
357
+                        exp_width: e,
358
+                    })
359
+                }
360
+                'S' => {
361
+                    chars.next();
362
+                    parse_real_desc(chars, |w, d, e| FormatDesc::RealES {
363
+                        width: w,
364
+                        decimals: d,
365
+                        exp_width: e,
366
+                    })
367
+                }
368
+                'X' => {
369
+                    chars.next();
370
+                    parse_real_desc(chars, |w, d, e| FormatDesc::RealEX {
371
+                        width: w,
372
+                        decimals: d,
373
+                        exp_width: e,
374
+                    })
375
+                }
376
+                _ => parse_real_desc(chars, |w, d, e| FormatDesc::RealE {
377
+                    width: w,
378
+                    decimals: d,
379
+                    exp_width: e,
380
+                }),
266381
             }
267382
         }
268383
         'D' => {
269384
             // DC/DP (decimal mode) vs DT (derived type) vs Dw.d (real format).
270385
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
271386
             match next {
272
-                'C' => { chars.next(); Some(FormatDesc::DecimalMode(DecimalSep::Comma)) }
273
-                'P' => { chars.next(); Some(FormatDesc::DecimalMode(DecimalSep::Point)) }
387
+                'C' => {
388
+                    chars.next();
389
+                    Some(FormatDesc::DecimalMode(DecimalSep::Comma))
390
+                }
391
+                'P' => {
392
+                    chars.next();
393
+                    Some(FormatDesc::DecimalMode(DecimalSep::Point))
394
+                }
274395
                 'T' => {
275396
                     chars.next();
276397
                     // DT optionally followed by 'typename'.
@@ -284,14 +405,24 @@ fn parse_edit_descriptor(
284405
                 }
285406
                 _ => {
286407
                     let w = parse_number(chars).unwrap_or(0);
287
-                    let d = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars).unwrap_or(0) } else { 0 };
288
-                    Some(FormatDesc::RealD { width: w, decimals: d })
408
+                    let d = if chars.peek() == Some(&'.') {
409
+                        chars.next();
410
+                        parse_number(chars).unwrap_or(0)
411
+                    } else {
412
+                        0
413
+                    };
414
+                    Some(FormatDesc::RealD {
415
+                        width: w,
416
+                        decimals: d,
417
+                    })
289418
                 }
290419
             }
291420
         }
292
-        'G' => {
293
-            parse_real_desc(chars, |w, d, e| FormatDesc::RealG { width: w, decimals: d, exp_width: e })
294
-        }
421
+        'G' => parse_real_desc(chars, |w, d, e| FormatDesc::RealG {
422
+            width: w,
423
+            decimals: d,
424
+            exp_width: e,
425
+        }),
295426
         'L' => {
296427
             let w = parse_number(chars).unwrap_or(1);
297428
             Some(FormatDesc::Logical { width: w })
@@ -300,22 +431,39 @@ fn parse_edit_descriptor(
300431
             let w = parse_number(chars);
301432
             Some(FormatDesc::Character { width: w })
302433
         }
303
-        'X' => {
304
-            Some(FormatDesc::Skip { count: repeat.unwrap_or(1) })
305
-        }
434
+        'X' => Some(FormatDesc::Skip {
435
+            count: repeat.unwrap_or(1),
436
+        }),
306437
         'T' => {
307438
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
308439
             match next {
309
-                'L' => { chars.next(); let n = parse_number(chars).unwrap_or(1); Some(FormatDesc::TabLeft { count: n }) }
310
-                'R' => { chars.next(); let n = parse_number(chars).unwrap_or(1); Some(FormatDesc::TabRight { count: n }) }
311
-                _ => { let n = parse_number(chars).unwrap_or(1); Some(FormatDesc::TabTo { position: n }) }
440
+                'L' => {
441
+                    chars.next();
442
+                    let n = parse_number(chars).unwrap_or(1);
443
+                    Some(FormatDesc::TabLeft { count: n })
444
+                }
445
+                'R' => {
446
+                    chars.next();
447
+                    let n = parse_number(chars).unwrap_or(1);
448
+                    Some(FormatDesc::TabRight { count: n })
449
+                }
450
+                _ => {
451
+                    let n = parse_number(chars).unwrap_or(1);
452
+                    Some(FormatDesc::TabTo { position: n })
453
+                }
312454
             }
313455
         }
314456
         'S' => {
315457
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
316458
             match next {
317
-                'P' => { chars.next(); Some(FormatDesc::Sign(SignMode::Plus)) }
318
-                'S' => { chars.next(); Some(FormatDesc::Sign(SignMode::Suppress)) }
459
+                'P' => {
460
+                    chars.next();
461
+                    Some(FormatDesc::Sign(SignMode::Plus))
462
+                }
463
+                'S' => {
464
+                    chars.next();
465
+                    Some(FormatDesc::Sign(SignMode::Suppress))
466
+                }
319467
                 _ => Some(FormatDesc::Sign(SignMode::Default)),
320468
             }
321469
         }
@@ -328,12 +476,30 @@ fn parse_edit_descriptor(
328476
             // Rounding modes: RU, RD, RZ, RN, RC, RP.
329477
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
330478
             let mode = match next {
331
-                'U' => { chars.next(); Some(RoundMode::Up) }
332
-                'D' => { chars.next(); Some(RoundMode::Down) }
333
-                'Z' => { chars.next(); Some(RoundMode::Zero) }
334
-                'N' => { chars.next(); Some(RoundMode::Nearest) }
335
-                'C' => { chars.next(); Some(RoundMode::Compatible) }
336
-                'P' => { chars.next(); Some(RoundMode::ProcessorDefined) }
479
+                'U' => {
480
+                    chars.next();
481
+                    Some(RoundMode::Up)
482
+                }
483
+                'D' => {
484
+                    chars.next();
485
+                    Some(RoundMode::Down)
486
+                }
487
+                'Z' => {
488
+                    chars.next();
489
+                    Some(RoundMode::Zero)
490
+                }
491
+                'N' => {
492
+                    chars.next();
493
+                    Some(RoundMode::Nearest)
494
+                }
495
+                'C' => {
496
+                    chars.next();
497
+                    Some(RoundMode::Compatible)
498
+                }
499
+                'P' => {
500
+                    chars.next();
501
+                    Some(RoundMode::ProcessorDefined)
502
+                }
337503
                 _ => None,
338504
             };
339505
             mode.map(FormatDesc::RoundingMode)
@@ -342,8 +508,14 @@ fn parse_edit_descriptor(
342508
             // BN or BZ.
343509
             let next = chars.peek().copied().unwrap_or(' ').to_ascii_uppercase();
344510
             match next {
345
-                'N' => { chars.next(); Some(FormatDesc::BlankMode(BlankInterpretation::Null)) }
346
-                'Z' => { chars.next(); Some(FormatDesc::BlankMode(BlankInterpretation::Zero)) }
511
+                'N' => {
512
+                    chars.next();
513
+                    Some(FormatDesc::BlankMode(BlankInterpretation::Null))
514
+                }
515
+                'Z' => {
516
+                    chars.next();
517
+                    Some(FormatDesc::BlankMode(BlankInterpretation::Zero))
518
+                }
347519
                 _ => None,
348520
             }
349521
         }
@@ -356,11 +528,22 @@ fn parse_real_desc(
356528
     constructor: impl Fn(usize, usize, Option<usize>) -> FormatDesc,
357529
 ) -> Option<FormatDesc> {
358530
     let w = parse_number(chars).unwrap_or(0);
359
-    let d = if chars.peek() == Some(&'.') { chars.next(); parse_number(chars).unwrap_or(0) } else { 0 };
360
-    let e = if chars.peek().map(|c| c.eq_ignore_ascii_case(&'E')).unwrap_or(false) {
531
+    let d = if chars.peek() == Some(&'.') {
532
+        chars.next();
533
+        parse_number(chars).unwrap_or(0)
534
+    } else {
535
+        0
536
+    };
537
+    let e = if chars
538
+        .peek()
539
+        .map(|c| c.eq_ignore_ascii_case(&'E'))
540
+        .unwrap_or(false)
541
+    {
361542
         chars.next();
362543
         parse_number(chars)
363
-    } else { None };
544
+    } else {
545
+        None
546
+    };
364547
     Some(constructor(w, d, e))
365548
 }
366549
 
@@ -413,22 +596,38 @@ impl FormatEngine {
413596
             match desc {
414597
                 // ---- Control descriptors ----
415598
                 FormatDesc::Skip { count } => {
416
-                    for _ in 0..*count { output.push(' '); }
599
+                    for _ in 0..*count {
600
+                        output.push(' ');
601
+                    }
602
+                }
603
+                FormatDesc::Newline => {
604
+                    output.push('\n');
417605
                 }
418
-                FormatDesc::Newline => { output.push('\n'); }
419606
                 FormatDesc::Colon => {
420
-                    if *val_idx >= values.len() { return; }
607
+                    if *val_idx >= values.len() {
608
+                        return;
609
+                    }
610
+                }
611
+                FormatDesc::Sign(mode) => {
612
+                    self.sign_mode = *mode;
613
+                }
614
+                FormatDesc::ScaleFactor(k) => {
615
+                    self.scale_factor = *k;
421616
                 }
422
-                FormatDesc::Sign(mode) => { self.sign_mode = *mode; }
423
-                FormatDesc::ScaleFactor(k) => { self.scale_factor = *k; }
424617
                 FormatDesc::BlankMode(_) => {} // input only
425
-                FormatDesc::RoundingMode(mode) => { self.round_mode = *mode; }
426
-                FormatDesc::DecimalMode(sep) => { self.decimal_sep = *sep; }
618
+                FormatDesc::RoundingMode(mode) => {
619
+                    self.round_mode = *mode;
620
+                }
621
+                FormatDesc::DecimalMode(sep) => {
622
+                    self.decimal_sep = *sep;
623
+                }
427624
                 FormatDesc::DerivedType { .. } => {} // requires user-defined I/O — no-op for now
428625
                 FormatDesc::TabTo { position } => {
429626
                     let cur_col = output.lines().last().map(|l| l.len()).unwrap_or(0);
430627
                     if *position > cur_col + 1 {
431
-                        for _ in 0..(*position - cur_col - 1) { output.push(' '); }
628
+                        for _ in 0..(*position - cur_col - 1) {
629
+                            output.push(' ');
630
+                        }
432631
                     }
433632
                 }
434633
                 FormatDesc::TabLeft { count } => {
@@ -437,12 +636,19 @@ impl FormatEngine {
437636
                     output.truncate(new_len);
438637
                 }
439638
                 FormatDesc::TabRight { count } => {
440
-                    for _ in 0..*count { output.push(' '); }
639
+                    for _ in 0..*count {
640
+                        output.push(' ');
641
+                    }
642
+                }
643
+                FormatDesc::LiteralString(s) => {
644
+                    output.push_str(s);
441645
                 }
442
-                FormatDesc::LiteralString(s) => { output.push_str(s); }
443646
 
444647
                 // ---- Group repeat ----
445
-                FormatDesc::Group { repeat, descriptors } => {
648
+                FormatDesc::Group {
649
+                    repeat,
650
+                    descriptors,
651
+                } => {
446652
                     for _ in 0..*repeat {
447653
                         self.apply_descriptors(descriptors, values, val_idx, output);
448654
                     }
@@ -455,7 +661,9 @@ impl FormatEngine {
455661
 
456662
                 // ---- Data descriptors ----
457663
                 _ => {
458
-                    if *val_idx >= values.len() { return; }
664
+                    if *val_idx >= values.len() {
665
+                        return;
666
+                    }
459667
                     let val = &values[*val_idx];
460668
                     *val_idx += 1;
461669
                     let formatted = self.format_value(desc, val);
@@ -472,7 +680,11 @@ impl FormatEngine {
472680
                 let s = if let Some(m) = min_digits {
473681
                     let abs_s = format!("{}", v.unsigned_abs());
474682
                     let padded = format!("{:0>width$}", abs_s, width = *m);
475
-                    if *v < 0 { format!("-{}", padded) } else { self.apply_sign(&padded, *v >= 0) }
683
+                    if *v < 0 {
684
+                        format!("-{}", padded)
685
+                    } else {
686
+                        self.apply_sign(&padded, *v >= 0)
687
+                    }
476688
                 } else {
477689
                     self.apply_sign(&format!("{}", v.unsigned_abs()), *v >= 0)
478690
                 };
@@ -496,16 +708,35 @@ impl FormatEngine {
496708
                 let s = self.format_fixed(rounded, *decimals);
497709
                 self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
498710
             }
499
-            (FormatDesc::RealE { width, decimals, exp_width }, IoValue::Real(v)) => {
711
+            (
712
+                FormatDesc::RealE {
713
+                    width,
714
+                    decimals,
715
+                    exp_width,
716
+                },
717
+                IoValue::Real(v),
718
+            ) => {
500719
                 let s = self.format_e_style(*v, *decimals, *exp_width, 'E');
501720
                 self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
502721
             }
503
-            (FormatDesc::RealES { width, decimals, exp_width }, IoValue::Real(v)) => {
722
+            (
723
+                FormatDesc::RealES {
724
+                    width,
725
+                    decimals,
726
+                    exp_width,
727
+                },
728
+                IoValue::Real(v),
729
+            ) => {
504730
                 // Scientific: mantissa in [1.0, 10.0). Equivalent to 1P,E.
505731
                 let s = self.format_es_style(*v, *decimals, *exp_width);
506732
                 self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
507733
             }
508
-            (FormatDesc::RealEN { width, decimals, .. }, IoValue::Real(v)) => {
734
+            (
735
+                FormatDesc::RealEN {
736
+                    width, decimals, ..
737
+                },
738
+                IoValue::Real(v),
739
+            ) => {
509740
                 // Engineering: exponent is multiple of 3.
510741
                 let (mantissa, exp) = to_engineering(*v);
511742
                 let rounded = self.apply_rounding(mantissa, *decimals);
@@ -516,7 +747,14 @@ impl FormatEngine {
516747
                 let s = self.format_e_style(*v, *decimals, None, 'D');
517748
                 self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
518749
             }
519
-            (FormatDesc::RealG { width, decimals, exp_width }, IoValue::Real(v)) => {
750
+            (
751
+                FormatDesc::RealG {
752
+                    width,
753
+                    decimals,
754
+                    exp_width,
755
+                },
756
+                IoValue::Real(v),
757
+            ) => {
520758
                 // G format: use F if magnitude fits, else E.
521759
                 let abs_v = v.abs();
522760
                 if abs_v == 0.0 || (abs_v >= 0.1 && abs_v < 10f64.powi(*decimals as i32)) {
@@ -528,7 +766,12 @@ impl FormatEngine {
528766
                     self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
529767
                 }
530768
             }
531
-            (FormatDesc::RealEX { width, decimals, .. }, IoValue::Real(v)) => {
769
+            (
770
+                FormatDesc::RealEX {
771
+                    width, decimals, ..
772
+                },
773
+                IoValue::Real(v),
774
+            ) => {
532775
                 // Hex-significand: use %a-like format. Rust doesn't have this natively.
533776
                 let s = format!("{:.*E}", *decimals, v); // fallback to E format
534777
                 self.apply_decimal_sep(&format!("{:>width$}", s, width = *width))
@@ -616,10 +859,23 @@ impl FormatEngine {
616859
     /// Fortran kP with E format: the mantissa is multiplied by 10^k,
617860
     /// and the exponent is decreased by k. With 0P (default), the mantissa
618861
     /// is in [0.1, 1.0) — Fortran's convention, not C's.
619
-    fn format_e_style(&self, v: f64, decimals: usize, exp_width: Option<usize>, exp_char: char) -> String {
862
+    fn format_e_style(
863
+        &self,
864
+        v: f64,
865
+        decimals: usize,
866
+        exp_width: Option<usize>,
867
+        exp_char: char,
868
+    ) -> String {
620869
         if v == 0.0 {
621870
             let ew = exp_width.unwrap_or(2);
622
-            return format!("0.{:0>d$}{}{:+0ew$}", "", exp_char, 0, d = decimals, ew = ew + 1);
871
+            return format!(
872
+                "0.{:0>d$}{}{:+0ew$}",
873
+                "",
874
+                exp_char,
875
+                0,
876
+                d = decimals,
877
+                ew = ew + 1
878
+            );
623879
         }
624880
 
625881
         let abs_v = v.abs();
@@ -630,8 +886,22 @@ impl FormatEngine {
630886
         let rounded = self.apply_rounding(mantissa, decimals);
631887
 
632888
         let ew = exp_width.unwrap_or(2);
633
-        let sign = if v < 0.0 { "-" } else if matches!(self.sign_mode, SignMode::Plus) { "+" } else { "" };
634
-        format!("{}{:.*}{}{:+0ew$}", sign, decimals, rounded, exp_char, fort_exp, ew = ew + 1)
889
+        let sign = if v < 0.0 {
890
+            "-"
891
+        } else if matches!(self.sign_mode, SignMode::Plus) {
892
+            "+"
893
+        } else {
894
+            ""
895
+        };
896
+        format!(
897
+            "{}{:.*}{}{:+0ew$}",
898
+            sign,
899
+            decimals,
900
+            rounded,
901
+            exp_char,
902
+            fort_exp,
903
+            ew = ew + 1
904
+        )
635905
     }
636906
 
637907
     /// Format in ES style (scientific): mantissa in [1.0, 10.0).
@@ -647,8 +917,21 @@ impl FormatEngine {
647917
         let rounded = self.apply_rounding(mantissa, decimals);
648918
 
649919
         let ew = exp_width.unwrap_or(2);
650
-        let sign = if v < 0.0 { "-" } else if matches!(self.sign_mode, SignMode::Plus) { "+" } else { "" };
651
-        format!("{}{:.*}E{:+0ew$}", sign, decimals, rounded, base_exp, ew = ew + 1)
920
+        let sign = if v < 0.0 {
921
+            "-"
922
+        } else if matches!(self.sign_mode, SignMode::Plus) {
923
+            "+"
924
+        } else {
925
+            ""
926
+        };
927
+        format!(
928
+            "{}{:.*}E{:+0ew$}",
929
+            sign,
930
+            decimals,
931
+            rounded,
932
+            base_exp,
933
+            ew = ew + 1
934
+        )
652935
     }
653936
 
654937
     /// Replace '.' with ',' when decimal mode is DC (comma).
@@ -663,14 +946,18 @@ impl FormatEngine {
663946
 // ---- Helpers ----
664947
 
665948
 fn to_engineering(v: f64) -> (f64, i32) {
666
-    if v == 0.0 { return (0.0, 0); }
949
+    if v == 0.0 {
950
+        return (0.0, 0);
951
+    }
667952
     let exp = (v.abs().log10().floor() as i32) / 3 * 3;
668953
     let mantissa = v / 10f64.powi(exp);
669954
     (mantissa, exp)
670955
 }
671956
 
672957
 fn skip_spaces(chars: &mut std::iter::Peekable<std::str::Chars>) {
673
-    while chars.peek() == Some(&' ') { chars.next(); }
958
+    while chars.peek() == Some(&' ') {
959
+        chars.next();
960
+    }
674961
 }
675962
 
676963
 fn parse_number(chars: &mut std::iter::Peekable<std::str::Chars>) -> Option<usize> {
@@ -683,7 +970,11 @@ fn parse_number(chars: &mut std::iter::Peekable<std::str::Chars>) -> Option<usiz
683970
             break;
684971
         }
685972
     }
686
-    if digits.is_empty() { None } else { digits.parse().ok() }
973
+    if digits.is_empty() {
974
+        None
975
+    } else {
976
+        digits.parse().ok()
977
+    }
687978
 }
688979
 
689980
 fn parse_string_literal(chars: &mut std::iter::Peekable<std::str::Chars>, quote: char) -> String {
@@ -711,10 +1002,14 @@ fn collect_until_matching_paren(chars: &mut std::iter::Peekable<std::str::Chars>
7111002
     let mut inner = String::new();
7121003
     while let Some(&c) = chars.peek() {
7131004
         chars.next();
714
-        if c == '(' { depth += 1; }
1005
+        if c == '(' {
1006
+            depth += 1;
1007
+        }
7151008
         if c == ')' {
7161009
             depth -= 1;
717
-            if depth == 0 { break; }
1010
+            if depth == 0 {
1011
+                break;
1012
+            }
7181013
         }
7191014
         inner.push(c);
7201015
     }
@@ -729,8 +1024,20 @@ mod tests {
7291024
     fn parse_simple_format() {
7301025
         let descs = parse_format("(I5, F10.3, A)");
7311026
         assert_eq!(descs.len(), 3);
732
-        assert!(matches!(descs[0], FormatDesc::IntegerI { width: 5, min_digits: None }));
733
-        assert!(matches!(descs[1], FormatDesc::RealF { width: 10, decimals: 3 }));
1027
+        assert!(matches!(
1028
+            descs[0],
1029
+            FormatDesc::IntegerI {
1030
+                width: 5,
1031
+                min_digits: None
1032
+            }
1033
+        ));
1034
+        assert!(matches!(
1035
+            descs[1],
1036
+            FormatDesc::RealF {
1037
+                width: 10,
1038
+                decimals: 3
1039
+            }
1040
+        ));
7341041
         assert!(matches!(descs[2], FormatDesc::Character { width: None }));
7351042
     }
7361043
 
@@ -757,14 +1064,30 @@ mod tests {
7571064
         assert_eq!(descs.len(), 2);
7581065
         if let FormatDesc::LiteralString(s) = &descs[0] {
7591066
             assert_eq!(s, "hello");
760
-        } else { panic!("expected literal"); }
1067
+        } else {
1068
+            panic!("expected literal");
1069
+        }
7611070
     }
7621071
 
7631072
     #[test]
7641073
     fn parse_es_en_format() {
7651074
         let descs = parse_format("(ES15.8, EN12.3)");
766
-        assert!(matches!(descs[0], FormatDesc::RealES { width: 15, decimals: 8, .. }));
767
-        assert!(matches!(descs[1], FormatDesc::RealEN { width: 12, decimals: 3, .. }));
1075
+        assert!(matches!(
1076
+            descs[0],
1077
+            FormatDesc::RealES {
1078
+                width: 15,
1079
+                decimals: 8,
1080
+                ..
1081
+            }
1082
+        ));
1083
+        assert!(matches!(
1084
+            descs[1],
1085
+            FormatDesc::RealEN {
1086
+                width: 12,
1087
+                decimals: 3,
1088
+                ..
1089
+            }
1090
+        ));
7681091
     }
7691092
 
7701093
     #[test]
@@ -869,7 +1192,9 @@ mod tests {
8691192
         let descs = parse_format("(*(I3, ','))");
8701193
         let mut engine = FormatEngine::new(descs);
8711194
         let out = engine.format_values(&[
872
-            IoValue::Integer(1), IoValue::Integer(2), IoValue::Integer(3)
1195
+            IoValue::Integer(1),
1196
+            IoValue::Integer(2),
1197
+            IoValue::Integer(3),
8731198
         ]);
8741199
         assert_eq!(out, "  1,  2,  3,");
8751200
     }
@@ -878,8 +1203,14 @@ mod tests {
8781203
     fn parse_dc_dp_decimal_mode() {
8791204
         let descs = parse_format("(DC, F8.3, DP, F8.3)");
8801205
         assert_eq!(descs.len(), 4);
881
-        assert!(matches!(descs[0], FormatDesc::DecimalMode(DecimalSep::Comma)));
882
-        assert!(matches!(descs[2], FormatDesc::DecimalMode(DecimalSep::Point)));
1206
+        assert!(matches!(
1207
+            descs[0],
1208
+            FormatDesc::DecimalMode(DecimalSep::Comma)
1209
+        ));
1210
+        assert!(matches!(
1211
+            descs[2],
1212
+            FormatDesc::DecimalMode(DecimalSep::Point)
1213
+        ));
8831214
     }
8841215
 
8851216
     #[test]
@@ -908,11 +1239,26 @@ mod tests {
9081239
     fn parse_rounding_modes() {
9091240
         let descs = parse_format("(RU, F8.3, RD, F8.3, RZ, F8.3, RN, F8.3, RC, F8.3, RP, F8.3)");
9101241
         assert!(matches!(descs[0], FormatDesc::RoundingMode(RoundMode::Up)));
911
-        assert!(matches!(descs[2], FormatDesc::RoundingMode(RoundMode::Down)));
912
-        assert!(matches!(descs[4], FormatDesc::RoundingMode(RoundMode::Zero)));
913
-        assert!(matches!(descs[6], FormatDesc::RoundingMode(RoundMode::Nearest)));
914
-        assert!(matches!(descs[8], FormatDesc::RoundingMode(RoundMode::Compatible)));
915
-        assert!(matches!(descs[10], FormatDesc::RoundingMode(RoundMode::ProcessorDefined)));
1242
+        assert!(matches!(
1243
+            descs[2],
1244
+            FormatDesc::RoundingMode(RoundMode::Down)
1245
+        ));
1246
+        assert!(matches!(
1247
+            descs[4],
1248
+            FormatDesc::RoundingMode(RoundMode::Zero)
1249
+        ));
1250
+        assert!(matches!(
1251
+            descs[6],
1252
+            FormatDesc::RoundingMode(RoundMode::Nearest)
1253
+        ));
1254
+        assert!(matches!(
1255
+            descs[8],
1256
+            FormatDesc::RoundingMode(RoundMode::Compatible)
1257
+        ));
1258
+        assert!(matches!(
1259
+            descs[10],
1260
+            FormatDesc::RoundingMode(RoundMode::ProcessorDefined)
1261
+        ));
9161262
     }
9171263
 
9181264
     #[test]
@@ -976,22 +1322,39 @@ mod tests {
9761322
     #[test]
9771323
     fn format_d_descriptor() {
9781324
         let descs = parse_format("(D12.5)");
979
-        assert!(matches!(descs[0], FormatDesc::RealD { width: 12, decimals: 5 }));
1325
+        assert!(matches!(
1326
+            descs[0],
1327
+            FormatDesc::RealD {
1328
+                width: 12,
1329
+                decimals: 5
1330
+            }
1331
+        ));
9801332
     }
9811333
 
9821334
     #[test]
9831335
     fn format_d_vs_dc() {
9841336
         // D12.5 is a real descriptor; DC is decimal comma mode.
9851337
         let descs = parse_format("(DC, D12.5)");
986
-        assert!(matches!(descs[0], FormatDesc::DecimalMode(DecimalSep::Comma)));
987
-        assert!(matches!(descs[1], FormatDesc::RealD { width: 12, decimals: 5 }));
1338
+        assert!(matches!(
1339
+            descs[0],
1340
+            FormatDesc::DecimalMode(DecimalSep::Comma)
1341
+        ));
1342
+        assert!(matches!(
1343
+            descs[1],
1344
+            FormatDesc::RealD {
1345
+                width: 12,
1346
+                decimals: 5
1347
+            }
1348
+        ));
9881349
     }
9891350
 
9901351
     #[test]
9911352
     fn format_integer16_full_width() {
9921353
         let descs = parse_format("(I40)");
9931354
         let mut engine = FormatEngine::new(descs);
994
-        let out = engine.format_values(&[IoValue::Integer(170141183460469231731687303715884105727i128)]);
1355
+        let out = engine.format_values(&[IoValue::Integer(
1356
+            170141183460469231731687303715884105727i128,
1357
+        )]);
9951358
         assert_eq!(out, " 170141183460469231731687303715884105727");
9961359
     }
9971360
 }
runtime/src/io_system.rsmodified
2387 lines changed — click to load
@@ -11,7 +11,7 @@
1111
 
1212
 use std::collections::HashMap;
1313
 use std::fs::{File, OpenOptions};
14
-use std::io::{self, Read, Write, BufRead, BufReader, BufWriter, Seek, SeekFrom};
14
+use std::io::{self, BufRead, BufReader, BufWriter, Read, Seek, SeekFrom, Write};
1515
 use std::sync::Mutex;
1616
 
1717
 // ---- Global I/O state ----
@@ -46,7 +46,6 @@ enum UnitStatus {
4646
     Open,
4747
 }
4848
 
49
-
5049
 #[derive(Debug, Clone, Copy, PartialEq)]
5150
 enum Access {
5251
     Sequential,
@@ -110,7 +109,12 @@ impl Unit {
110109
             UnitStream::FileRaw(f) => {
111110
                 f.write_all(data)?;
112111
             }
113
-            _ => return Err(io::Error::new(io::ErrorKind::PermissionDenied, "unit not open for writing")),
112
+            _ => {
113
+                return Err(io::Error::new(
114
+                    io::ErrorKind::PermissionDenied,
115
+                    "unit not open for writing",
116
+                ))
117
+            }
114118
         }
115119
         Ok(())
116120
     }
@@ -143,7 +147,12 @@ impl Unit {
143147
                     }
144148
                 }
145149
             }
146
-            _ => return Err(io::Error::new(io::ErrorKind::PermissionDenied, "unit not open for reading")),
150
+            _ => {
151
+                return Err(io::Error::new(
152
+                    io::ErrorKind::PermissionDenied,
153
+                    "unit not open for reading",
154
+                ))
155
+            }
147156
         }
148157
         Ok(line)
149158
     }
@@ -197,44 +206,56 @@ impl IoState {
197206
         let mut units = HashMap::new();
198207
 
199208
         // Preconnected units.
200
-        units.insert(5, Unit {
201
-            _number: 5,
202
-            stream: UnitStream::Stdin,
203
-            filename: "stdin".into(),
204
-            _status: UnitStatus::Open,
205
-            access: Access::Sequential,
206
-            form: Form::Formatted,
207
-            action: Action::Read,
208
-            recl: None,
209
-            read_tokens: Vec::new(),
210
-            formatted_read_record: None,
211
-        });
212
-        units.insert(6, Unit {
213
-            _number: 6,
214
-            stream: UnitStream::Stdout,
215
-            filename: "stdout".into(),
216
-            _status: UnitStatus::Open,
217
-            access: Access::Sequential,
218
-            form: Form::Formatted,
219
-            action: Action::Write,
220
-            recl: None,
221
-            read_tokens: Vec::new(),
222
-            formatted_read_record: None,
223
-        });
224
-        units.insert(0, Unit {
225
-            _number: 0,
226
-            stream: UnitStream::Stderr,
227
-            filename: "stderr".into(),
228
-            _status: UnitStatus::Open,
229
-            access: Access::Sequential,
230
-            form: Form::Formatted,
231
-            action: Action::Write,
232
-            recl: None,
233
-            read_tokens: Vec::new(),
234
-            formatted_read_record: None,
235
-        });
209
+        units.insert(
210
+            5,
211
+            Unit {
212
+                _number: 5,
213
+                stream: UnitStream::Stdin,
214
+                filename: "stdin".into(),
215
+                _status: UnitStatus::Open,
216
+                access: Access::Sequential,
217
+                form: Form::Formatted,
218
+                action: Action::Read,
219
+                recl: None,
220
+                read_tokens: Vec::new(),
221
+                formatted_read_record: None,
222
+            },
223
+        );
224
+        units.insert(
225
+            6,
226
+            Unit {
227
+                _number: 6,
228
+                stream: UnitStream::Stdout,
229
+                filename: "stdout".into(),
230
+                _status: UnitStatus::Open,
231
+                access: Access::Sequential,
232
+                form: Form::Formatted,
233
+                action: Action::Write,
234
+                recl: None,
235
+                read_tokens: Vec::new(),
236
+                formatted_read_record: None,
237
+            },
238
+        );
239
+        units.insert(
240
+            0,
241
+            Unit {
242
+                _number: 0,
243
+                stream: UnitStream::Stderr,
244
+                filename: "stderr".into(),
245
+                _status: UnitStatus::Open,
246
+                access: Access::Sequential,
247
+                form: Form::Formatted,
248
+                action: Action::Write,
249
+                recl: None,
250
+                read_tokens: Vec::new(),
251
+                formatted_read_record: None,
252
+            },
253
+        );
236254
 
237
-        Self { units, next_newunit: -10 }
255
+        Self {
256
+            units,
257
+            next_newunit: -10,
258
+        }
238259
     }
239260
 
240261
     fn get_unit(&mut self, unit_num: i32) -> Option<&mut Unit> {
@@ -277,20 +298,30 @@ pub struct OpenControlBlock {
277298
 #[no_mangle]
278299
 pub extern "C" fn afs_open_simple(
279300
     unit: i32,
280
-    filename: *const u8, filename_len: i64,
281
-    status: *const u8, status_len: i64,
282
-    action: *const u8, action_len: i64,
301
+    filename: *const u8,
302
+    filename_len: i64,
303
+    status: *const u8,
304
+    status_len: i64,
305
+    action: *const u8,
306
+    action_len: i64,
283307
 ) {
284308
     let cb = OpenControlBlock {
285
-        unit, filename, filename_len,
286
-        status, status_len,
287
-        action, action_len,
288
-        access: std::ptr::null(), access_len: 0,
289
-        form: std::ptr::null(), form_len: 0,
309
+        unit,
310
+        filename,
311
+        filename_len,
312
+        status,
313
+        status_len,
314
+        action,
315
+        action_len,
316
+        access: std::ptr::null(),
317
+        access_len: 0,
318
+        form: std::ptr::null(),
319
+        form_len: 0,
290320
         recl: 0,
291321
         iostat: std::ptr::null_mut(),
292322
         newunit: std::ptr::null_mut(),
293
-        position: std::ptr::null(), position_len: 0,
323
+        position: std::ptr::null(),
324
+        position_len: 0,
294325
     };
295326
     afs_open(&cb);
296327
 }
@@ -299,7 +330,9 @@ pub extern "C" fn afs_open_simple(
299330
 /// exceeding the 8-register ARM64 calling convention limit.
300331
 #[no_mangle]
301332
 pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
302
-    if cb.is_null() { return; }
333
+    if cb.is_null() {
334
+        return;
335
+    }
303336
     let cb = unsafe { &*cb };
304337
     let unit = cb.unit;
305338
     let fname = unsafe_str(cb.filename, cb.filename_len);
@@ -317,7 +350,9 @@ pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
317350
     // NEWUNIT: allocate a new unit number.
318351
     let actual_unit = if !newunit.is_null() {
319352
         let u = state.alloc_newunit();
320
-        unsafe { *newunit = u; }
353
+        unsafe {
354
+            *newunit = u;
355
+        }
321356
         u
322357
     } else {
323358
         unit
@@ -326,11 +361,21 @@ pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
326361
     // Build OpenOptions based on status/action.
327362
     let mut opts = OpenOptions::new();
328363
     match status_str.trim() {
329
-        "old" => { opts.read(true); }
330
-        "new" => { opts.write(true).create_new(true); }
331
-        "replace" => { opts.write(true).create(true).truncate(true); }
332
-        "scratch" | "unknown" | "" => { opts.read(true).write(true).create(true); }
333
-        _ => { opts.read(true).write(true).create(true); }
364
+        "old" => {
365
+            opts.read(true);
366
+        }
367
+        "new" => {
368
+            opts.write(true).create_new(true);
369
+        }
370
+        "replace" => {
371
+            opts.write(true).create(true).truncate(true);
372
+        }
373
+        "scratch" | "unknown" | "" => {
374
+            opts.read(true).write(true).create(true);
375
+        }
376
+        _ => {
377
+            opts.read(true).write(true).create(true);
378
+        }
334379
     }
335380
 
336381
     // Determine action. Default depends on status:
@@ -348,9 +393,15 @@ pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
348393
     };
349394
 
350395
     match effective_action {
351
-        "read" => { opts.read(true); }
352
-        "write" => { opts.write(true).create(true); }
353
-        _ => { opts.read(true).write(true).create(true); }
396
+        "read" => {
397
+            opts.read(true);
398
+        }
399
+        "write" => {
400
+            opts.write(true).create(true);
401
+        }
402
+        _ => {
403
+            opts.read(true).write(true).create(true);
404
+        }
354405
     }
355406
 
356407
     // Flush and close existing unit if re-opening.
@@ -386,18 +437,21 @@ pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
386437
                     Action::ReadWrite => UnitStream::FileRaw(file),
387438
                 },
388439
             };
389
-            state.units.insert(actual_unit, Unit {
390
-                _number: actual_unit,
391
-                stream,
392
-                filename: fname,
393
-                _status: UnitStatus::Open,
394
-                access: file_access,
395
-                form: file_form,
396
-                action: file_action,
397
-                recl: if recl > 0 { Some(recl) } else { None },
398
-                read_tokens: Vec::new(),
399
-                formatted_read_record: None,
400
-            });
440
+            state.units.insert(
441
+                actual_unit,
442
+                Unit {
443
+                    _number: actual_unit,
444
+                    stream,
445
+                    filename: fname,
446
+                    _status: UnitStatus::Open,
447
+                    access: file_access,
448
+                    form: file_form,
449
+                    action: file_action,
450
+                    recl: if recl > 0 { Some(recl) } else { None },
451
+                    read_tokens: Vec::new(),
452
+                    formatted_read_record: None,
453
+                },
454
+            );
401455
 
402456
             // Apply POSITION specifier.
403457
             // Default: REWIND for sequential, ASIS for direct/stream.
@@ -414,19 +468,31 @@ pub extern "C" fn afs_open(cb: *const OpenControlBlock) {
414468
             if let Some(seek) = pos {
415469
                 if let Some(u) = state.get_unit(actual_unit) {
416470
                     match &mut u.stream {
417
-                        UnitStream::FileRaw(f) => { let _ = f.seek(seek); }
418
-                        UnitStream::FileRead(r) => { let _ = r.seek(seek); }
419
-                        UnitStream::FileWrite(w) => { let _ = w.seek(seek); }
471
+                        UnitStream::FileRaw(f) => {
472
+                            let _ = f.seek(seek);
473
+                        }
474
+                        UnitStream::FileRead(r) => {
475
+                            let _ = r.seek(seek);
476
+                        }
477
+                        UnitStream::FileWrite(w) => {
478
+                            let _ = w.seek(seek);
479
+                        }
420480
                         _ => {}
421481
                     }
422482
                 }
423483
             }
424484
 
425
-            if !iostat.is_null() { unsafe { *iostat = 0; } }
485
+            if !iostat.is_null() {
486
+                unsafe {
487
+                    *iostat = 0;
488
+                }
489
+            }
426490
         }
427491
         Err(e) => {
428492
             if !iostat.is_null() {
429
-                unsafe { *iostat = e.raw_os_error().unwrap_or(1); }
493
+                unsafe {
494
+                    *iostat = e.raw_os_error().unwrap_or(1);
495
+                }
430496
             } else {
431497
                 eprintln!("OPEN: {}: {}", fname, e);
432498
                 std::process::exit(1);
@@ -442,9 +508,17 @@ pub extern "C" fn afs_close(unit: i32, iostat: *mut i32) {
442508
     if let Some(mut u) = state.units.remove(&unit) {
443509
         let _ = u.flush();
444510
         // File is dropped here, closing the handle.
445
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
511
+        if !iostat.is_null() {
512
+            unsafe {
513
+                *iostat = 0;
514
+            }
515
+        }
446516
     } else {
447
-        if !iostat.is_null() { unsafe { *iostat = 0; } } // closing unopen unit is not an error
517
+        if !iostat.is_null() {
518
+            unsafe {
519
+                *iostat = 0;
520
+            }
521
+        } // closing unopen unit is not an error
448522
     }
449523
 }
450524
 
@@ -558,25 +632,49 @@ pub extern "C" fn afs_read_int(unit: i32, val: *mut i32, iostat: *mut i32) {
558632
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
559633
     if let Some(u) = state.get_unit(unit) {
560634
         match u.next_read_token() {
561
-            Ok(Some(token)) => {
562
-                match token.parse::<i32>() {
563
-                    Ok(v) => {
564
-                        if !val.is_null() { unsafe { *val = v; } }
565
-                        if !iostat.is_null() { unsafe { *iostat = 0; } }
635
+            Ok(Some(token)) => match token.parse::<i32>() {
636
+                Ok(v) => {
637
+                    if !val.is_null() {
638
+                        unsafe {
639
+                            *val = v;
640
+                        }
566641
                     }
567
-                    Err(_) => {
568
-                        if !iostat.is_null() { unsafe { *iostat = 1; } }
569
-                        else { eprintln!("READ: cannot parse integer from '{}'", token); std::process::exit(1); }
642
+                    if !iostat.is_null() {
643
+                        unsafe {
644
+                            *iostat = 0;
645
+                        }
570646
                     }
571647
                 }
572
-            }
648
+                Err(_) => {
649
+                    if !iostat.is_null() {
650
+                        unsafe {
651
+                            *iostat = 1;
652
+                        }
653
+                    } else {
654
+                        eprintln!("READ: cannot parse integer from '{}'", token);
655
+                        std::process::exit(1);
656
+                    }
657
+                }
658
+            },
573659
             Ok(None) => {
574
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
575
-                else { eprintln!("READ: end of file"); std::process::exit(1); }
660
+                if !iostat.is_null() {
661
+                    unsafe {
662
+                        *iostat = IOSTAT_END;
663
+                    }
664
+                } else {
665
+                    eprintln!("READ: end of file");
666
+                    std::process::exit(1);
667
+                }
576668
             }
577669
             Err(e) => {
578
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
579
-                else { eprintln!("READ: {}", e); std::process::exit(1); }
670
+                if !iostat.is_null() {
671
+                    unsafe {
672
+                        *iostat = 1;
673
+                    }
674
+                } else {
675
+                    eprintln!("READ: {}", e);
676
+                    std::process::exit(1);
677
+                }
580678
             }
581679
         }
582680
     }
@@ -588,23 +686,43 @@ pub extern "C" fn afs_read_int64(unit: i32, val: *mut i64, iostat: *mut i32) {
588686
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
589687
     if let Some(u) = state.get_unit(unit) {
590688
         match u.next_read_token() {
591
-            Ok(Some(token)) => {
592
-                match token.parse::<i64>() {
593
-                    Ok(v) => {
594
-                        if !val.is_null() { unsafe { *val = v; } }
595
-                        if !iostat.is_null() { unsafe { *iostat = 0; } }
689
+            Ok(Some(token)) => match token.parse::<i64>() {
690
+                Ok(v) => {
691
+                    if !val.is_null() {
692
+                        unsafe {
693
+                            *val = v;
694
+                        }
596695
                     }
597
-                    Err(_) => {
598
-                        if !iostat.is_null() { unsafe { *iostat = 1; } }
599
-                        else { eprintln!("READ: cannot parse integer from '{}'", token); std::process::exit(1); }
696
+                    if !iostat.is_null() {
697
+                        unsafe {
698
+                            *iostat = 0;
699
+                        }
600700
                     }
601701
                 }
602
-            }
702
+                Err(_) => {
703
+                    if !iostat.is_null() {
704
+                        unsafe {
705
+                            *iostat = 1;
706
+                        }
707
+                    } else {
708
+                        eprintln!("READ: cannot parse integer from '{}'", token);
709
+                        std::process::exit(1);
710
+                    }
711
+                }
712
+            },
603713
             Ok(None) => {
604
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
714
+                if !iostat.is_null() {
715
+                    unsafe {
716
+                        *iostat = IOSTAT_END;
717
+                    }
718
+                }
605719
             }
606720
             Err(_) => {
607
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
721
+                if !iostat.is_null() {
722
+                    unsafe {
723
+                        *iostat = 1;
724
+                    }
725
+                }
608726
             }
609727
         }
610728
     }
@@ -616,23 +734,39 @@ pub extern "C" fn afs_read_int128(unit: i32, val: *mut i128, iostat: *mut i32) {
616734
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
617735
     if let Some(u) = state.get_unit(unit) {
618736
         match u.next_read_token() {
619
-            Ok(Some(token)) => {
620
-                match token.parse::<i128>() {
621
-                    Ok(v) => {
622
-                        write_i128_ptr(val, v);
623
-                        if !iostat.is_null() { unsafe { *iostat = 0; } }
737
+            Ok(Some(token)) => match token.parse::<i128>() {
738
+                Ok(v) => {
739
+                    write_i128_ptr(val, v);
740
+                    if !iostat.is_null() {
741
+                        unsafe {
742
+                            *iostat = 0;
743
+                        }
624744
                     }
625
-                    Err(_) => {
626
-                        if !iostat.is_null() { unsafe { *iostat = 1; } }
627
-                        else { eprintln!("READ: cannot parse integer from '{}'", token); std::process::exit(1); }
745
+                }
746
+                Err(_) => {
747
+                    if !iostat.is_null() {
748
+                        unsafe {
749
+                            *iostat = 1;
750
+                        }
751
+                    } else {
752
+                        eprintln!("READ: cannot parse integer from '{}'", token);
753
+                        std::process::exit(1);
628754
                     }
629755
                 }
630
-            }
756
+            },
631757
             Ok(None) => {
632
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
758
+                if !iostat.is_null() {
759
+                    unsafe {
760
+                        *iostat = IOSTAT_END;
761
+                    }
762
+                }
633763
             }
634764
             Err(_) => {
635
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
765
+                if !iostat.is_null() {
766
+                    unsafe {
767
+                        *iostat = 1;
768
+                    }
769
+                }
636770
             }
637771
         }
638772
     }
@@ -649,21 +783,45 @@ pub extern "C" fn afs_read_real(unit: i32, val: *mut f32, iostat: *mut i32) {
649783
                 let normalized = token.replace('d', "e").replace('D', "E");
650784
                 match normalized.parse::<f32>() {
651785
                     Ok(v) => {
652
-                        if !val.is_null() { unsafe { *val = v; } }
653
-                        if !iostat.is_null() { unsafe { *iostat = 0; } }
786
+                        if !val.is_null() {
787
+                            unsafe {
788
+                                *val = v;
789
+                            }
790
+                        }
791
+                        if !iostat.is_null() {
792
+                            unsafe {
793
+                                *iostat = 0;
794
+                            }
795
+                        }
654796
                     }
655797
                     Err(_) => {
656
-                        if !iostat.is_null() { unsafe { *iostat = 1; } }
657
-                        else { eprintln!("READ: cannot parse real from '{}'", token); std::process::exit(1); }
798
+                        if !iostat.is_null() {
799
+                            unsafe {
800
+                                *iostat = 1;
801
+                            }
802
+                        } else {
803
+                            eprintln!("READ: cannot parse real from '{}'", token);
804
+                            std::process::exit(1);
805
+                        }
658806
                     }
659807
                 }
660808
             }
661809
             Ok(None) => {
662
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
663
-                else { eprintln!("READ: end of file"); std::process::exit(1); }
810
+                if !iostat.is_null() {
811
+                    unsafe {
812
+                        *iostat = IOSTAT_END;
813
+                    }
814
+                } else {
815
+                    eprintln!("READ: end of file");
816
+                    std::process::exit(1);
817
+                }
664818
             }
665819
             Err(_) => {
666
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
820
+                if !iostat.is_null() {
821
+                    unsafe {
822
+                        *iostat = 1;
823
+                    }
824
+                }
667825
             }
668826
         }
669827
     }
@@ -679,20 +837,42 @@ pub extern "C" fn afs_read_real64(unit: i32, val: *mut f64, iostat: *mut i32) {
679837
                 let normalized = token.replace('d', "e").replace('D', "E");
680838
                 match normalized.parse::<f64>() {
681839
                     Ok(v) => {
682
-                        if !val.is_null() { unsafe { *val = v; } }
683
-                        if !iostat.is_null() { unsafe { *iostat = 0; } }
840
+                        if !val.is_null() {
841
+                            unsafe {
842
+                                *val = v;
843
+                            }
844
+                        }
845
+                        if !iostat.is_null() {
846
+                            unsafe {
847
+                                *iostat = 0;
848
+                            }
849
+                        }
684850
                     }
685851
                     Err(_) => {
686
-                        if !iostat.is_null() { unsafe { *iostat = 1; } }
687
-                        else { eprintln!("READ: cannot parse real from '{}'", token); std::process::exit(1); }
852
+                        if !iostat.is_null() {
853
+                            unsafe {
854
+                                *iostat = 1;
855
+                            }
856
+                        } else {
857
+                            eprintln!("READ: cannot parse real from '{}'", token);
858
+                            std::process::exit(1);
859
+                        }
688860
                     }
689861
                 }
690862
             }
691863
             Ok(None) => {
692
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
864
+                if !iostat.is_null() {
865
+                    unsafe {
866
+                        *iostat = IOSTAT_END;
867
+                    }
868
+                }
693869
             }
694870
             Err(_) => {
695
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
871
+                if !iostat.is_null() {
872
+                    unsafe {
873
+                        *iostat = 1;
874
+                    }
875
+                }
696876
             }
697877
         }
698878
     }
@@ -716,22 +896,32 @@ impl Unit {
716896
     /// Record numbers are 1-based. Returns Ok(()) or Err on failure.
717897
     fn seek_to_record(&mut self, rec: i64) -> io::Result<()> {
718898
         if rec < 1 {
719
-            return Err(io::Error::new(io::ErrorKind::InvalidInput,
720
-                "direct access record number must be >= 1"));
721
-        }
722
-        let recl = self.recl.ok_or_else(||
723
-            io::Error::new(io::ErrorKind::InvalidInput, "direct access requires RECL"))?;
724
-        let offset = (rec - 1).checked_mul(recl).ok_or_else(||
725
-            io::Error::new(io::ErrorKind::InvalidInput, "record offset overflow"))?;
899
+            return Err(io::Error::new(
900
+                io::ErrorKind::InvalidInput,
901
+                "direct access record number must be >= 1",
902
+            ));
903
+        }
904
+        let recl = self.recl.ok_or_else(|| {
905
+            io::Error::new(io::ErrorKind::InvalidInput, "direct access requires RECL")
906
+        })?;
907
+        let offset = (rec - 1)
908
+            .checked_mul(recl)
909
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "record offset overflow"))?;
726910
         if offset < 0 {
727
-            return Err(io::Error::new(io::ErrorKind::InvalidInput, "negative record offset"));
911
+            return Err(io::Error::new(
912
+                io::ErrorKind::InvalidInput,
913
+                "negative record offset",
914
+            ));
728915
         }
729916
         match &mut self.stream {
730917
             UnitStream::FileRaw(f) => {
731918
                 f.seek(SeekFrom::Start(offset as u64))?;
732919
                 Ok(())
733920
             }
734
-            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "unit not opened for direct access")),
921
+            _ => Err(io::Error::new(
922
+                io::ErrorKind::InvalidInput,
923
+                "unit not opened for direct access",
924
+            )),
735925
         }
736926
     }
737927
 
@@ -740,7 +930,10 @@ impl Unit {
740930
         match &mut self.stream {
741931
             UnitStream::FileRaw(f) => f.write_all(data),
742932
             UnitStream::FileWrite(w) => w.write_all(data),
743
-            _ => Err(io::Error::new(io::ErrorKind::PermissionDenied, "unit not open for writing")),
933
+            _ => Err(io::Error::new(
934
+                io::ErrorKind::PermissionDenied,
935
+                "unit not open for writing",
936
+            )),
744937
         }
745938
     }
746939
 
@@ -749,7 +942,10 @@ impl Unit {
749942
         match &mut self.stream {
750943
             UnitStream::FileRaw(f) => f.read(buf),
751944
             UnitStream::FileRead(r) => r.read(buf),
752
-            _ => Err(io::Error::new(io::ErrorKind::PermissionDenied, "unit not open for reading")),
945
+            _ => Err(io::Error::new(
946
+                io::ErrorKind::PermissionDenied,
947
+                "unit not open for reading",
948
+            )),
753949
         }
754950
     }
755951
 }
@@ -757,44 +953,72 @@ impl Unit {
757953
 /// Write a direct-access record (formatted string padded to recl).
758954
 #[no_mangle]
759955
 pub extern "C" fn afs_write_direct(
760
-    unit: i32, rec: i64,
761
-    data: *const u8, data_len: i64,
956
+    unit: i32,
957
+    rec: i64,
958
+    data: *const u8,
959
+    data_len: i64,
762960
     iostat: *mut i32,
763961
 ) {
764962
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
765963
     if let Some(u) = state.get_unit(unit) {
766964
         if let Err(e) = u.seek_to_record(rec) {
767
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
768
-            else { eprintln!("WRITE direct: {}", e); std::process::exit(1); }
965
+            if !iostat.is_null() {
966
+                unsafe {
967
+                    *iostat = 1;
968
+                }
969
+            } else {
970
+                eprintln!("WRITE direct: {}", e);
971
+                std::process::exit(1);
972
+            }
769973
             return;
770974
         }
771975
         let recl = u.recl.unwrap_or(0) as usize;
772976
         let mut record = vec![b' '; recl]; // space-padded
773977
         let copy_len = (data_len as usize).min(recl);
774978
         if !data.is_null() && copy_len > 0 {
775
-            unsafe { std::ptr::copy_nonoverlapping(data, record.as_mut_ptr(), copy_len); }
979
+            unsafe {
980
+                std::ptr::copy_nonoverlapping(data, record.as_mut_ptr(), copy_len);
981
+            }
776982
         }
777983
         if let Err(e) = u.write_raw(&record) {
778
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
779
-            else { eprintln!("WRITE direct: {}", e); std::process::exit(1); }
984
+            if !iostat.is_null() {
985
+                unsafe {
986
+                    *iostat = 1;
987
+                }
988
+            } else {
989
+                eprintln!("WRITE direct: {}", e);
990
+                std::process::exit(1);
991
+            }
780992
             return;
781993
         }
782
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
994
+        if !iostat.is_null() {
995
+            unsafe {
996
+                *iostat = 0;
997
+            }
998
+        }
783999
     }
7841000
 }
7851001
 
7861002
 /// Read a direct-access record.
7871003
 #[no_mangle]
7881004
 pub extern "C" fn afs_read_direct(
789
-    unit: i32, rec: i64,
790
-    data: *mut u8, data_len: i64,
1005
+    unit: i32,
1006
+    rec: i64,
1007
+    data: *mut u8,
1008
+    data_len: i64,
7911009
     iostat: *mut i32,
7921010
 ) {
7931011
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
7941012
     if let Some(u) = state.get_unit(unit) {
7951013
         if let Err(e) = u.seek_to_record(rec) {
796
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
797
-            else { eprintln!("READ direct: {}", e); std::process::exit(1); }
1014
+            if !iostat.is_null() {
1015
+                unsafe {
1016
+                    *iostat = 1;
1017
+                }
1018
+            } else {
1019
+                eprintln!("READ direct: {}", e);
1020
+                std::process::exit(1);
1021
+            }
7981022
             return;
7991023
         }
8001024
         let recl = u.recl.unwrap_or(0) as usize;
@@ -803,17 +1027,35 @@ pub extern "C" fn afs_read_direct(
8031027
             Ok(n) => {
8041028
                 let copy_len = n.min(data_len as usize);
8051029
                 if !data.is_null() && copy_len > 0 {
806
-                    unsafe { std::ptr::copy_nonoverlapping(record.as_ptr(), data, copy_len); }
1030
+                    unsafe {
1031
+                        std::ptr::copy_nonoverlapping(record.as_ptr(), data, copy_len);
1032
+                    }
8071033
                 }
8081034
                 // Pad remainder with spaces.
8091035
                 if copy_len < data_len as usize {
810
-                    unsafe { std::ptr::write_bytes(data.add(copy_len), b' ', data_len as usize - copy_len); }
1036
+                    unsafe {
1037
+                        std::ptr::write_bytes(
1038
+                            data.add(copy_len),
1039
+                            b' ',
1040
+                            data_len as usize - copy_len,
1041
+                        );
1042
+                    }
1043
+                }
1044
+                if !iostat.is_null() {
1045
+                    unsafe {
1046
+                        *iostat = 0;
1047
+                    }
8111048
                 }
812
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
8131049
             }
8141050
             Err(e) => {
815
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
816
-                else { eprintln!("READ direct: {}", e); std::process::exit(1); }
1051
+                if !iostat.is_null() {
1052
+                    unsafe {
1053
+                        *iostat = 1;
1054
+                    }
1055
+                } else {
1056
+                    eprintln!("READ direct: {}", e);
1057
+                    std::process::exit(1);
1058
+                }
8171059
             }
8181060
         }
8191061
     }
@@ -825,14 +1067,24 @@ pub extern "C" fn afs_read_direct(
8251067
 #[no_mangle]
8261068
 pub extern "C" fn afs_write_unformatted(
8271069
     unit: i32,
828
-    data: *const u8, data_len: i64,
1070
+    data: *const u8,
1071
+    data_len: i64,
8291072
     iostat: *mut i32,
8301073
 ) {
8311074
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
8321075
     if let Some(u) = state.get_unit(unit) {
8331076
         if data_len < 0 || data_len > u32::MAX as i64 {
834
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
835
-            else { eprintln!("WRITE unformatted: record length {} exceeds 4GB limit", data_len); std::process::exit(1); }
1077
+            if !iostat.is_null() {
1078
+                unsafe {
1079
+                    *iostat = 1;
1080
+                }
1081
+            } else {
1082
+                eprintln!(
1083
+                    "WRITE unformatted: record length {} exceeds 4GB limit",
1084
+                    data_len
1085
+                );
1086
+                std::process::exit(1);
1087
+            }
8361088
             return;
8371089
         }
8381090
         let len_bytes = (data_len as u32).to_ne_bytes();
@@ -841,12 +1093,22 @@ pub extern "C" fn afs_write_unformatted(
8411093
         let r2 = if !data.is_null() && data_len > 0 {
8421094
             let slice = unsafe { std::slice::from_raw_parts(data, data_len as usize) };
8431095
             u.write_raw(slice)
844
-        } else { Ok(()) };
1096
+        } else {
1097
+            Ok(())
1098
+        };
8451099
         let r3 = u.write_raw(&len_bytes);
8461100
         if r1.is_err() || r2.is_err() || r3.is_err() {
847
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
1101
+            if !iostat.is_null() {
1102
+                unsafe {
1103
+                    *iostat = 1;
1104
+                }
1105
+            }
8481106
         } else {
849
-            if !iostat.is_null() { unsafe { *iostat = 0; } }
1107
+            if !iostat.is_null() {
1108
+                unsafe {
1109
+                    *iostat = 0;
1110
+                }
1111
+            }
8501112
         }
8511113
     }
8521114
 }
@@ -855,7 +1117,8 @@ pub extern "C" fn afs_write_unformatted(
8551117
 #[no_mangle]
8561118
 pub extern "C" fn afs_read_unformatted(
8571119
     unit: i32,
858
-    data: *mut u8, max_len: i64,
1120
+    data: *mut u8,
1121
+    max_len: i64,
8591122
     actual_len: *mut i64,
8601123
     iostat: *mut i32,
8611124
 ) {
@@ -866,16 +1129,28 @@ pub extern "C" fn afs_read_unformatted(
8661129
         match u.read_raw(&mut len_buf) {
8671130
             Ok(4) => {}
8681131
             Ok(0) => {
869
-                if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
1132
+                if !iostat.is_null() {
1133
+                    unsafe {
1134
+                        *iostat = IOSTAT_END;
1135
+                    }
1136
+                }
8701137
                 return;
8711138
             }
8721139
             _ => {
873
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
1140
+                if !iostat.is_null() {
1141
+                    unsafe {
1142
+                        *iostat = 1;
1143
+                    }
1144
+                }
8741145
                 return;
8751146
             }
8761147
         }
8771148
         let record_len = u32::from_ne_bytes(len_buf) as usize;
878
-        if !actual_len.is_null() { unsafe { *actual_len = record_len as i64; } }
1149
+        if !actual_len.is_null() {
1150
+            unsafe {
1151
+                *actual_len = record_len as i64;
1152
+            }
1153
+        }
8791154
 
8801155
         // Read record data.
8811156
         let read_len = record_len.min(max_len as usize);
@@ -892,7 +1167,11 @@ pub extern "C" fn afs_read_unformatted(
8921167
 
8931168
         // Read trailing length marker (and discard).
8941169
         let _ = u.read_raw(&mut len_buf);
895
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
1170
+        if !iostat.is_null() {
1171
+            unsafe {
1172
+                *iostat = 0;
1173
+            }
1174
+        }
8961175
     }
8971176
 }
8981177
 
@@ -900,18 +1179,26 @@ pub extern "C" fn afs_read_unformatted(
9001179
 
9011180
 /// Write raw bytes at the current stream position.
9021181
 #[no_mangle]
903
-pub extern "C" fn afs_write_stream(
904
-    unit: i32,
905
-    data: *const u8, data_len: i64,
906
-    iostat: *mut i32,
907
-) {
1182
+pub extern "C" fn afs_write_stream(unit: i32, data: *const u8, data_len: i64, iostat: *mut i32) {
9081183
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
9091184
     if let Some(u) = state.get_unit(unit) {
9101185
         if !data.is_null() && data_len > 0 {
9111186
             let slice = unsafe { std::slice::from_raw_parts(data, data_len as usize) };
9121187
             match u.write_raw(slice) {
913
-                Ok(()) => { if !iostat.is_null() { unsafe { *iostat = 0; } } }
914
-                Err(_) => { if !iostat.is_null() { unsafe { *iostat = 1; } } }
1188
+                Ok(()) => {
1189
+                    if !iostat.is_null() {
1190
+                        unsafe {
1191
+                            *iostat = 0;
1192
+                        }
1193
+                    }
1194
+                }
1195
+                Err(_) => {
1196
+                    if !iostat.is_null() {
1197
+                        unsafe {
1198
+                            *iostat = 1;
1199
+                        }
1200
+                    }
1201
+                }
9151202
             }
9161203
         }
9171204
     }
@@ -923,13 +1210,29 @@ pub extern "C" fn afs_seek_stream(unit: i32, pos: i64, iostat: *mut i32) {
9231210
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
9241211
     if let Some(u) = state.get_unit(unit) {
9251212
         match &mut u.stream {
926
-            UnitStream::FileRaw(f) => {
927
-                match f.seek(SeekFrom::Start(pos as u64)) {
928
-                    Ok(_) => { if !iostat.is_null() { unsafe { *iostat = 0; } } }
929
-                    Err(_) => { if !iostat.is_null() { unsafe { *iostat = 1; } } }
1213
+            UnitStream::FileRaw(f) => match f.seek(SeekFrom::Start(pos as u64)) {
1214
+                Ok(_) => {
1215
+                    if !iostat.is_null() {
1216
+                        unsafe {
1217
+                            *iostat = 0;
1218
+                        }
1219
+                    }
1220
+                }
1221
+                Err(_) => {
1222
+                    if !iostat.is_null() {
1223
+                        unsafe {
1224
+                            *iostat = 1;
1225
+                        }
1226
+                    }
1227
+                }
1228
+            },
1229
+            _ => {
1230
+                if !iostat.is_null() {
1231
+                    unsafe {
1232
+                        *iostat = 1;
1233
+                    }
9301234
                 }
9311235
             }
932
-            _ => { if !iostat.is_null() { unsafe { *iostat = 1; } } }
9331236
         }
9341237
     }
9351238
 }
@@ -942,8 +1245,8 @@ pub struct NamelistEntry {
9421245
     pub name: *const u8,
9431246
     pub name_len: i64,
9441247
     pub data: *mut u8,
945
-    pub data_type: i32,  // 0=int, 1=real, 2=string, 3=logical
946
-    pub data_len: i64,   // string length for type 2
1248
+    pub data_type: i32, // 0=int, 1=real, 2=string, 3=logical
1249
+    pub data_len: i64,  // string length for type 2
9471250
 }
9481251
 
9491252
 /// Write a NAMELIST group to a unit.
@@ -951,8 +1254,10 @@ pub struct NamelistEntry {
9511254
 #[no_mangle]
9521255
 pub extern "C" fn afs_write_namelist(
9531256
     unit: i32,
954
-    group_name: *const u8, group_name_len: i64,
955
-    entries: *const NamelistEntry, n_entries: i32,
1257
+    group_name: *const u8,
1258
+    group_name_len: i64,
1259
+    entries: *const NamelistEntry,
1260
+    n_entries: i32,
9561261
 ) {
9571262
     let gname = unsafe_str(group_name, group_name_len);
9581263
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
@@ -965,19 +1270,23 @@ pub extern "C" fn afs_write_namelist(
9651270
                 let name = unsafe_str(entry.name, entry.name_len);
9661271
                 let sep = if i > 0 { "," } else { "" };
9671272
                 let val_str = match entry.data_type {
968
-                    0 => { // integer
1273
+                    0 => {
1274
+                        // integer
9691275
                         let v = unsafe { *(entry.data as *const i32) };
9701276
                         format!("{}", v)
9711277
                     }
972
-                    1 => { // real
1278
+                    1 => {
1279
+                        // real
9731280
                         let v = unsafe { *(entry.data as *const f64) };
9741281
                         format!("{}", v)
9751282
                     }
976
-                    2 => { // string
1283
+                    2 => {
1284
+                        // string
9771285
                         let s = unsafe_str(entry.data, entry.data_len);
9781286
                         format!("'{}'", s.trim_end())
9791287
                     }
980
-                    3 => { // logical
1288
+                    3 => {
1289
+                        // logical
9811290
                         let v = unsafe { *(entry.data as *const i32) };
9821291
                         (if v != 0 { ".TRUE." } else { ".FALSE." }).to_string()
9831292
                     }
@@ -996,8 +1305,10 @@ pub extern "C" fn afs_write_namelist(
9961305
 #[no_mangle]
9971306
 pub extern "C" fn afs_read_namelist(
9981307
     unit: i32,
999
-    group_name: *const u8, group_name_len: i64,
1000
-    entries: *const NamelistEntry, n_entries: i32,
1308
+    group_name: *const u8,
1309
+    group_name_len: i64,
1310
+    entries: *const NamelistEntry,
1311
+    n_entries: i32,
10011312
     iostat: *mut i32,
10021313
 ) {
10031314
     let gname = unsafe_str(group_name, group_name_len).to_lowercase();
@@ -1022,7 +1333,11 @@ pub extern "C" fn afs_read_namelist(
10221333
                     }
10231334
                 }
10241335
                 Err(_) => {
1025
-                    if !iostat.is_null() { unsafe { *iostat = IOSTAT_END; } }
1336
+                    if !iostat.is_null() {
1337
+                        unsafe {
1338
+                            *iostat = IOSTAT_END;
1339
+                        }
1340
+                    }
10261341
                     return;
10271342
                 }
10281343
             }
@@ -1036,8 +1351,12 @@ pub extern "C" fn afs_read_namelist(
10361351
                 let after_name = &all_lines[start + gname.len()..];
10371352
                 if let Some(end) = after_name.find('/') {
10381353
                     &after_name[..end]
1039
-                } else { after_name }
1040
-            } else { "" };
1354
+                } else {
1355
+                    after_name
1356
+                }
1357
+            } else {
1358
+                ""
1359
+            };
10411360
 
10421361
             // Parse var=val pairs. Supports:
10431362
             //   var=val            — simple scalar assignment
@@ -1047,12 +1366,12 @@ pub extern "C" fn afs_read_namelist(
10471366
                 let pair = pair.trim();
10481367
                 if let Some(eq_pos) = pair.find('=') {
10491368
                     let lhs = pair[..eq_pos].trim().to_lowercase();
1050
-                    let val_str = pair[eq_pos+1..].trim();
1369
+                    let val_str = pair[eq_pos + 1..].trim();
10511370
 
10521371
                     // Parse array index from "var(idx)" syntax.
10531372
                     let (var_name, array_index) = if let Some(paren) = lhs.find('(') {
10541373
                         let name = lhs[..paren].trim();
1055
-                        let idx_str = lhs[paren+1..].trim_end_matches(')').trim();
1374
+                        let idx_str = lhs[paren + 1..].trim_end_matches(')').trim();
10561375
                         let idx = idx_str.parse::<usize>().unwrap_or(1);
10571376
                         (name.to_string(), Some(idx))
10581377
                     } else {
@@ -1064,7 +1383,7 @@ pub extern "C" fn afs_read_namelist(
10641383
                         // Make sure * is preceded by digits (not part of a number like 1.5E*).
10651384
                         let before = val_str[..star].trim();
10661385
                         if let Ok(n) = before.parse::<usize>() {
1067
-                            (n, val_str[star+1..].trim())
1386
+                            (n, val_str[star + 1..].trim())
10681387
                         } else {
10691388
                             (1, val_str)
10701389
                         }
@@ -1074,7 +1393,9 @@ pub extern "C" fn afs_read_namelist(
10741393
 
10751394
                     // Find the matching entry.
10761395
                     for entry in entries_slice {
1077
-                        if entry.data.is_null() { continue; }
1396
+                        if entry.data.is_null() {
1397
+                            continue;
1398
+                        }
10781399
                         let ename = unsafe_str(entry.name, entry.name_len).to_lowercase();
10791400
                         if ename == var_name {
10801401
                             namelist_assign_value(entry, actual_val, array_index, repeat_count);
@@ -1084,37 +1405,55 @@ pub extern "C" fn afs_read_namelist(
10841405
                 }
10851406
             }
10861407
         }
1087
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
1408
+        if !iostat.is_null() {
1409
+            unsafe {
1410
+                *iostat = 0;
1411
+            }
1412
+        }
10881413
     }
10891414
 }
10901415
 
10911416
 /// Assign a parsed NAMELIST value to an entry, handling array indexing and repeat.
1092
-fn namelist_assign_value(entry: &NamelistEntry, val_str: &str, index: Option<usize>, repeat: usize) {
1417
+fn namelist_assign_value(
1418
+    entry: &NamelistEntry,
1419
+    val_str: &str,
1420
+    index: Option<usize>,
1421
+    repeat: usize,
1422
+) {
10931423
     // For array elements, compute byte offset from 1-based index.
10941424
     let elem_size = match entry.data_type {
1095
-        0 => 4,  // integer (i32)
1096
-        1 => 8,  // real (f64)
1097
-        3 => 4,  // logical (i32)
1098
-        _ => 1,  // string
1425
+        0 => 4, // integer (i32)
1426
+        1 => 8, // real (f64)
1427
+        3 => 4, // logical (i32)
1428
+        _ => 1, // string
10991429
     };
1100
-    let base_offset = index.map(|i| (i.saturating_sub(1)) * elem_size).unwrap_or(0);
1430
+    let base_offset = index
1431
+        .map(|i| (i.saturating_sub(1)) * elem_size)
1432
+        .unwrap_or(0);
11011433
 
11021434
     for r in 0..repeat {
11031435
         let offset = base_offset + r * elem_size;
11041436
         let ptr = unsafe { entry.data.add(offset) };
11051437
         match entry.data_type {
1106
-            0 => { // integer
1438
+            0 => {
1439
+                // integer
11071440
                 if let Ok(v) = val_str.parse::<i32>() {
1108
-                    unsafe { *(ptr as *mut i32) = v; }
1441
+                    unsafe {
1442
+                        *(ptr as *mut i32) = v;
1443
+                    }
11091444
                 }
11101445
             }
1111
-            1 => { // real
1446
+            1 => {
1447
+                // real
11121448
                 let normalized = val_str.replace('d', "e").replace('D', "E");
11131449
                 if let Ok(v) = normalized.parse::<f64>() {
1114
-                    unsafe { *(ptr as *mut f64) = v; }
1450
+                    unsafe {
1451
+                        *(ptr as *mut f64) = v;
1452
+                    }
11151453
                 }
11161454
             }
1117
-            2 => { // string (only first element for repeat, no array stride for strings)
1455
+            2 => {
1456
+                // string (only first element for repeat, no array stride for strings)
11181457
                 let s = val_str.trim_matches('\'').trim_matches('"');
11191458
                 let bytes = s.as_bytes();
11201459
                 let copy_len = bytes.len().min(entry.data_len as usize);
@@ -1122,17 +1461,23 @@ fn namelist_assign_value(entry: &NamelistEntry, val_str: &str, index: Option<usi
11221461
                     unsafe {
11231462
                         std::ptr::copy_nonoverlapping(bytes.as_ptr(), entry.data, copy_len);
11241463
                         if copy_len < entry.data_len as usize {
1125
-                            std::ptr::write_bytes(entry.data.add(copy_len), b' ',
1126
-                                entry.data_len as usize - copy_len);
1464
+                            std::ptr::write_bytes(
1465
+                                entry.data.add(copy_len),
1466
+                                b' ',
1467
+                                entry.data_len as usize - copy_len,
1468
+                            );
11271469
                         }
11281470
                     }
11291471
                 }
11301472
                 return; // string repeat doesn't make sense
11311473
             }
1132
-            3 => { // logical
1474
+            3 => {
1475
+                // logical
11331476
                 let lower = val_str.to_lowercase();
11341477
                 let v = lower.starts_with(".t") || lower.starts_with("t");
1135
-                unsafe { *(ptr as *mut i32) = v as i32; }
1478
+                unsafe {
1479
+                    *(ptr as *mut i32) = v as i32;
1480
+                }
11361481
             }
11371482
             _ => {}
11381483
         }
@@ -1144,64 +1489,85 @@ fn namelist_assign_value(entry: &NamelistEntry, val_str: &str, index: Option<usi
11441489
 /// Write a formatted integer to a character buffer (internal I/O).
11451490
 #[no_mangle]
11461491
 pub extern "C" fn afs_write_internal_int(
1147
-    buf: *mut u8, buf_len: i64,
1492
+    buf: *mut u8,
1493
+    buf_len: i64,
11481494
     val: i32,
11491495
     pos: *mut i64, // current write position, updated after write
11501496
 ) {
1151
-    if buf.is_null() || buf_len <= 0 { return; }
1497
+    if buf.is_null() || buf_len <= 0 {
1498
+        return;
1499
+    }
11521500
     let s = format!(" {}", val);
1153
-    let start = if !pos.is_null() { (unsafe { *pos }) as usize } else { 0 };
1501
+    let start = if !pos.is_null() {
1502
+        (unsafe { *pos }) as usize
1503
+    } else {
1504
+        0
1505
+    };
11541506
     write_to_buffer(buf, buf_len as usize, start, s.as_bytes(), pos);
11551507
 }
11561508
 
11571509
 /// Write a formatted i64 to a character buffer (internal I/O).
11581510
 #[no_mangle]
1159
-pub extern "C" fn afs_write_internal_int64(
1160
-    buf: *mut u8, buf_len: i64,
1161
-    val: i64,
1162
-    pos: *mut i64,
1163
-) {
1164
-    if buf.is_null() || buf_len <= 0 { return; }
1511
+pub extern "C" fn afs_write_internal_int64(buf: *mut u8, buf_len: i64, val: i64, pos: *mut i64) {
1512
+    if buf.is_null() || buf_len <= 0 {
1513
+        return;
1514
+    }
11651515
     let s = format!(" {}", val);
1166
-    let start = if !pos.is_null() { (unsafe { *pos }) as usize } else { 0 };
1516
+    let start = if !pos.is_null() {
1517
+        (unsafe { *pos }) as usize
1518
+    } else {
1519
+        0
1520
+    };
11671521
     write_to_buffer(buf, buf_len as usize, start, s.as_bytes(), pos);
11681522
 }
11691523
 
11701524
 /// Write a formatted integer(16) to a character buffer (internal I/O).
11711525
 #[no_mangle]
1172
-pub extern "C" fn afs_write_internal_int128(
1173
-    buf: *mut u8, buf_len: i64,
1174
-    val: i128,
1175
-    pos: *mut i64,
1176
-) {
1177
-    if buf.is_null() || buf_len <= 0 { return; }
1526
+pub extern "C" fn afs_write_internal_int128(buf: *mut u8, buf_len: i64, val: i128, pos: *mut i64) {
1527
+    if buf.is_null() || buf_len <= 0 {
1528
+        return;
1529
+    }
11781530
     let s = format!(" {}", val);
1179
-    let start = if !pos.is_null() { (unsafe { *pos }) as usize } else { 0 };
1531
+    let start = if !pos.is_null() {
1532
+        (unsafe { *pos }) as usize
1533
+    } else {
1534
+        0
1535
+    };
11801536
     write_to_buffer(buf, buf_len as usize, start, s.as_bytes(), pos);
11811537
 }
11821538
 
11831539
 /// Write a formatted real to a character buffer (internal I/O).
11841540
 #[no_mangle]
1185
-pub extern "C" fn afs_write_internal_real64(
1186
-    buf: *mut u8, buf_len: i64,
1187
-    val: f64,
1188
-    pos: *mut i64,
1189
-) {
1190
-    if buf.is_null() || buf_len <= 0 { return; }
1541
+pub extern "C" fn afs_write_internal_real64(buf: *mut u8, buf_len: i64, val: f64, pos: *mut i64) {
1542
+    if buf.is_null() || buf_len <= 0 {
1543
+        return;
1544
+    }
11911545
     let s = format!(" {}", val);
1192
-    let start = if !pos.is_null() { (unsafe { *pos }) as usize } else { 0 };
1546
+    let start = if !pos.is_null() {
1547
+        (unsafe { *pos }) as usize
1548
+    } else {
1549
+        0
1550
+    };
11931551
     write_to_buffer(buf, buf_len as usize, start, s.as_bytes(), pos);
11941552
 }
11951553
 
11961554
 /// Write a formatted string to a character buffer (internal I/O).
11971555
 #[no_mangle]
11981556
 pub extern "C" fn afs_write_internal_string(
1199
-    buf: *mut u8, buf_len: i64,
1200
-    src: *const u8, src_len: i64,
1557
+    buf: *mut u8,
1558
+    buf_len: i64,
1559
+    src: *const u8,
1560
+    src_len: i64,
12011561
     pos: *mut i64,
12021562
 ) {
1203
-    if buf.is_null() || buf_len <= 0 { return; }
1204
-    let start = if !pos.is_null() { (unsafe { *pos }) as usize } else { 0 };
1563
+    if buf.is_null() || buf_len <= 0 {
1564
+        return;
1565
+    }
1566
+    let start = if !pos.is_null() {
1567
+        (unsafe { *pos }) as usize
1568
+    } else {
1569
+        0
1570
+    };
12051571
     let mut data = vec![b' '];
12061572
     if !src.is_null() && src_len > 0 {
12071573
         let slice = unsafe { std::slice::from_raw_parts(src, src_len as usize) };
@@ -1228,7 +1594,9 @@ fn next_internal_token(buf: *const u8, buf_len: i64, pos: *mut i64) -> Option<St
12281594
 
12291595
     if idx >= slice.len() {
12301596
         if !pos.is_null() {
1231
-            unsafe { *pos = idx as i64; }
1597
+            unsafe {
1598
+                *pos = idx as i64;
1599
+            }
12321600
         }
12331601
         return None;
12341602
     }
@@ -1239,7 +1607,9 @@ fn next_internal_token(buf: *const u8, buf_len: i64, pos: *mut i64) -> Option<St
12391607
     }
12401608
 
12411609
     if !pos.is_null() {
1242
-        unsafe { *pos = idx as i64; }
1610
+        unsafe {
1611
+            *pos = idx as i64;
1612
+        }
12431613
     }
12441614
 
12451615
     Some(String::from_utf8_lossy(&slice[start..idx]).into_owned())
@@ -1248,7 +1618,8 @@ fn next_internal_token(buf: *const u8, buf_len: i64, pos: *mut i64) -> Option<St
12481618
 /// Read an integer from a character buffer (internal I/O).
12491619
 #[no_mangle]
12501620
 pub extern "C" fn afs_read_internal_int(
1251
-    buf: *const u8, buf_len: i64,
1621
+    buf: *const u8,
1622
+    buf_len: i64,
12521623
     pos: *mut i64,
12531624
     val: *mut i32,
12541625
     iostat: *mut i32,
@@ -1256,22 +1627,39 @@ pub extern "C" fn afs_read_internal_int(
12561627
     if let Some(token) = next_internal_token(buf, buf_len, pos) {
12571628
         match token.replace(',', "").parse::<i32>() {
12581629
             Ok(v) => {
1259
-                if !val.is_null() { unsafe { *val = v; } }
1260
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1630
+                if !val.is_null() {
1631
+                    unsafe {
1632
+                        *val = v;
1633
+                    }
1634
+                }
1635
+                if !iostat.is_null() {
1636
+                    unsafe {
1637
+                        *iostat = 0;
1638
+                    }
1639
+                }
12611640
             }
12621641
             Err(_) => {
1263
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
1642
+                if !iostat.is_null() {
1643
+                    unsafe {
1644
+                        *iostat = 1;
1645
+                    }
1646
+                }
12641647
             }
12651648
         }
12661649
     } else {
1267
-        if !iostat.is_null() { unsafe { *iostat = -1; } }
1650
+        if !iostat.is_null() {
1651
+            unsafe {
1652
+                *iostat = -1;
1653
+            }
1654
+        }
12681655
     }
12691656
 }
12701657
 
12711658
 /// Read an i64 from a character buffer (internal I/O).
12721659
 #[no_mangle]
12731660
 pub extern "C" fn afs_read_internal_int64(
1274
-    buf: *const u8, buf_len: i64,
1661
+    buf: *const u8,
1662
+    buf_len: i64,
12751663
     pos: *mut i64,
12761664
     val: *mut i64,
12771665
     iostat: *mut i32,
@@ -1279,22 +1667,39 @@ pub extern "C" fn afs_read_internal_int64(
12791667
     if let Some(token) = next_internal_token(buf, buf_len, pos) {
12801668
         match token.replace(',', "").parse::<i64>() {
12811669
             Ok(v) => {
1282
-                if !val.is_null() { unsafe { *val = v; } }
1283
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1670
+                if !val.is_null() {
1671
+                    unsafe {
1672
+                        *val = v;
1673
+                    }
1674
+                }
1675
+                if !iostat.is_null() {
1676
+                    unsafe {
1677
+                        *iostat = 0;
1678
+                    }
1679
+                }
12841680
             }
12851681
             Err(_) => {
1286
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
1682
+                if !iostat.is_null() {
1683
+                    unsafe {
1684
+                        *iostat = 1;
1685
+                    }
1686
+                }
12871687
             }
12881688
         }
12891689
     } else {
1290
-        if !iostat.is_null() { unsafe { *iostat = -1; } }
1690
+        if !iostat.is_null() {
1691
+            unsafe {
1692
+                *iostat = -1;
1693
+            }
1694
+        }
12911695
     }
12921696
 }
12931697
 
12941698
 /// Read an integer(16) from a character buffer (internal I/O).
12951699
 #[no_mangle]
12961700
 pub extern "C" fn afs_read_internal_int128(
1297
-    buf: *const u8, buf_len: i64,
1701
+    buf: *const u8,
1702
+    buf_len: i64,
12981703
     pos: *mut i64,
12991704
     val: *mut i128,
13001705
     iostat: *mut i32,
@@ -1303,21 +1708,34 @@ pub extern "C" fn afs_read_internal_int128(
13031708
         match token.replace(',', "").parse::<i128>() {
13041709
             Ok(v) => {
13051710
                 write_i128_ptr(val, v);
1306
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1711
+                if !iostat.is_null() {
1712
+                    unsafe {
1713
+                        *iostat = 0;
1714
+                    }
1715
+                }
13071716
             }
13081717
             Err(_) => {
1309
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
1718
+                if !iostat.is_null() {
1719
+                    unsafe {
1720
+                        *iostat = 1;
1721
+                    }
1722
+                }
13101723
             }
13111724
         }
13121725
     } else {
1313
-        if !iostat.is_null() { unsafe { *iostat = -1; } }
1726
+        if !iostat.is_null() {
1727
+            unsafe {
1728
+                *iostat = -1;
1729
+            }
1730
+        }
13141731
     }
13151732
 }
13161733
 
13171734
 /// Read a real from a character buffer (internal I/O).
13181735
 #[no_mangle]
13191736
 pub extern "C" fn afs_read_internal_real(
1320
-    buf: *const u8, buf_len: i64,
1737
+    buf: *const u8,
1738
+    buf_len: i64,
13211739
     pos: *mut i64,
13221740
     val: *mut f64,
13231741
     iostat: *mut i32,
@@ -1326,15 +1744,31 @@ pub extern "C" fn afs_read_internal_real(
13261744
         let normalized = token.replace('d', "e").replace('D', "E").replace(',', "");
13271745
         match normalized.parse::<f64>() {
13281746
             Ok(v) => {
1329
-                if !val.is_null() { unsafe { *val = v; } }
1330
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1747
+                if !val.is_null() {
1748
+                    unsafe {
1749
+                        *val = v;
1750
+                    }
1751
+                }
1752
+                if !iostat.is_null() {
1753
+                    unsafe {
1754
+                        *iostat = 0;
1755
+                    }
1756
+                }
13311757
             }
13321758
             Err(_) => {
1333
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
1759
+                if !iostat.is_null() {
1760
+                    unsafe {
1761
+                        *iostat = 1;
1762
+                    }
1763
+                }
13341764
             }
13351765
         }
13361766
     } else {
1337
-        if !iostat.is_null() { unsafe { *iostat = -1; } }
1767
+        if !iostat.is_null() {
1768
+            unsafe {
1769
+                *iostat = -1;
1770
+            }
1771
+        }
13381772
     }
13391773
 }
13401774
 
@@ -1349,10 +1783,14 @@ fn write_to_buffer(buf: *mut u8, buf_len: usize, start: usize, data: &[u8], pos:
13491783
     // Space-pad remaining buffer.
13501784
     let end = start + copy_len;
13511785
     if end < buf_len {
1352
-        unsafe { std::ptr::write_bytes(buf.add(end), b' ', buf_len - end); }
1786
+        unsafe {
1787
+            std::ptr::write_bytes(buf.add(end), b' ', buf_len - end);
1788
+        }
13531789
     }
13541790
     if !pos.is_null() {
1355
-        unsafe { *pos = end as i64; }
1791
+        unsafe {
1792
+            *pos = end as i64;
1793
+        }
13561794
     }
13571795
 }
13581796
 
@@ -1370,7 +1808,11 @@ pub extern "C" fn afs_backspace(unit: i32, iostat: *mut i32) {
13701808
                 let pos = f.stream_position().unwrap_or(0);
13711809
                 if pos <= 1 {
13721810
                     let _ = f.seek(SeekFrom::Start(0));
1373
-                    if !iostat.is_null() { unsafe { *iostat = 0; } }
1811
+                    if !iostat.is_null() {
1812
+                        unsafe {
1813
+                            *iostat = 0;
1814
+                        }
1815
+                    }
13741816
                     // Clear stale read tokens.
13751817
                     u.read_tokens.clear();
13761818
                     return;
@@ -1380,7 +1822,9 @@ pub extern "C" fn afs_backspace(unit: i32, iostat: *mut i32) {
13801822
                 loop {
13811823
                     f.seek(SeekFrom::Start(search_pos)).ok();
13821824
                     let mut byte = [0u8; 1];
1383
-                    if f.read(&mut byte).unwrap_or(0) == 0 { break; }
1825
+                    if f.read(&mut byte).unwrap_or(0) == 0 {
1826
+                        break;
1827
+                    }
13841828
                     if byte[0] == b'\n' {
13851829
                         f.seek(SeekFrom::Start(search_pos + 1)).ok();
13861830
                         break;
@@ -1393,11 +1837,19 @@ pub extern "C" fn afs_backspace(unit: i32, iostat: *mut i32) {
13931837
                 }
13941838
                 // Clear stale read tokens after repositioning.
13951839
                 u.read_tokens.clear();
1396
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1840
+                if !iostat.is_null() {
1841
+                    unsafe {
1842
+                        *iostat = 0;
1843
+                    }
1844
+                }
13971845
             }
13981846
             _ => {
13991847
                 // Sequential buffered files: backspace is not well-supported.
1400
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1848
+                if !iostat.is_null() {
1849
+                    unsafe {
1850
+                        *iostat = 0;
1851
+                    }
1852
+                }
14011853
             }
14021854
         }
14031855
     }
@@ -1413,7 +1865,11 @@ pub extern "C" fn afs_endfile(unit: i32, iostat: *mut i32) {
14131865
             let pos = f.stream_position().unwrap_or(0);
14141866
             let _ = f.set_len(pos); // truncate at current position
14151867
         }
1416
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
1868
+        if !iostat.is_null() {
1869
+            unsafe {
1870
+                *iostat = 0;
1871
+            }
1872
+        }
14171873
     }
14181874
 }
14191875
 
@@ -1429,7 +1885,9 @@ pub const IOSTAT_EOR: i32 = -2;
14291885
 /// Write a Fortran-style string result into a caller-provided buffer.
14301886
 /// Pads with spaces to buf_len (Fortran CHARACTER semantics).
14311887
 fn write_inquire_string(buf: *mut u8, buf_len: i64, value: &str) {
1432
-    if buf.is_null() || buf_len <= 0 { return; }
1888
+    if buf.is_null() || buf_len <= 0 {
1889
+        return;
1890
+    }
14331891
     let n = buf_len as usize;
14341892
     let val_bytes = value.as_bytes();
14351893
     let copy_len = val_bytes.len().min(n);
@@ -1445,15 +1903,20 @@ fn write_inquire_string(buf: *mut u8, buf_len: i64, value: &str) {
14451903
 /// INQUIRE by file: check if a file exists, report its properties.
14461904
 #[no_mangle]
14471905
 pub extern "C" fn afs_inquire_file(
1448
-    filename: *const u8, filename_len: i64,
1906
+    filename: *const u8,
1907
+    filename_len: i64,
14491908
     exist: *mut i32,
14501909
     opened: *mut i32,
14511910
     iostat: *mut i32,
14521911
     // Extended specifiers — pass null for any not needed.
1453
-    name_buf: *mut u8, name_buf_len: i64,
1454
-    access_buf: *mut u8, access_buf_len: i64,
1455
-    form_buf: *mut u8, form_buf_len: i64,
1456
-    action_buf: *mut u8, action_buf_len: i64,
1912
+    name_buf: *mut u8,
1913
+    name_buf_len: i64,
1914
+    access_buf: *mut u8,
1915
+    access_buf_len: i64,
1916
+    form_buf: *mut u8,
1917
+    form_buf_len: i64,
1918
+    action_buf: *mut u8,
1919
+    action_buf_len: i64,
14571920
     recl_out: *mut i64,
14581921
     size_out: *mut i64,
14591922
 ) {
@@ -1461,7 +1924,9 @@ pub extern "C" fn afs_inquire_file(
14611924
 
14621925
     let file_exists = std::path::Path::new(&fname).exists();
14631926
     if !exist.is_null() {
1464
-        unsafe { *exist = file_exists as i32; }
1927
+        unsafe {
1928
+            *exist = file_exists as i32;
1929
+        }
14651930
     }
14661931
 
14671932
     // Find unit connected to this file (if any).
@@ -1469,14 +1934,24 @@ pub extern "C" fn afs_inquire_file(
14691934
     let connected_unit = state.units.values().find(|u| u.filename == fname);
14701935
 
14711936
     if !opened.is_null() {
1472
-        unsafe { *opened = connected_unit.is_some() as i32; }
1937
+        unsafe {
1938
+            *opened = connected_unit.is_some() as i32;
1939
+        }
14731940
     }
14741941
 
14751942
     write_inquire_string(name_buf, name_buf_len, &fname);
14761943
 
14771944
     if let Some(u) = connected_unit {
1478
-        write_unit_properties(u, access_buf, access_buf_len, form_buf, form_buf_len,
1479
-                              action_buf, action_buf_len, recl_out);
1945
+        write_unit_properties(
1946
+            u,
1947
+            access_buf,
1948
+            access_buf_len,
1949
+            form_buf,
1950
+            form_buf_len,
1951
+            action_buf,
1952
+            action_buf_len,
1953
+            recl_out,
1954
+        );
14801955
     } else {
14811956
         write_inquire_string(access_buf, access_buf_len, "UNDEFINED");
14821957
         write_inquire_string(form_buf, form_buf_len, "UNDEFINED");
@@ -1485,12 +1960,18 @@ pub extern "C" fn afs_inquire_file(
14851960
 
14861961
     // File size via metadata.
14871962
     if !size_out.is_null() {
1488
-        let sz = std::fs::metadata(&fname).map(|m| m.len() as i64).unwrap_or(-1);
1489
-        unsafe { *size_out = sz; }
1963
+        let sz = std::fs::metadata(&fname)
1964
+            .map(|m| m.len() as i64)
1965
+            .unwrap_or(-1);
1966
+        unsafe {
1967
+            *size_out = sz;
1968
+        }
14901969
     }
14911970
 
14921971
     if !iostat.is_null() {
1493
-        unsafe { *iostat = 0; }
1972
+        unsafe {
1973
+            *iostat = 0;
1974
+        }
14941975
     }
14951976
 }
14961977
 
@@ -1502,10 +1983,14 @@ pub extern "C" fn afs_inquire_unit(
15021983
     opened: *mut i32,
15031984
     iostat: *mut i32,
15041985
     // Extended specifiers.
1505
-    name_buf: *mut u8, name_buf_len: i64,
1506
-    access_buf: *mut u8, access_buf_len: i64,
1507
-    form_buf: *mut u8, form_buf_len: i64,
1508
-    action_buf: *mut u8, action_buf_len: i64,
1986
+    name_buf: *mut u8,
1987
+    name_buf_len: i64,
1988
+    access_buf: *mut u8,
1989
+    access_buf_len: i64,
1990
+    form_buf: *mut u8,
1991
+    form_buf_len: i64,
1992
+    action_buf: *mut u8,
1993
+    action_buf_len: i64,
15091994
     recl_out: *mut i64,
15101995
     size_out: *mut i64,
15111996
 ) {
@@ -1513,42 +1998,69 @@ pub extern "C" fn afs_inquire_unit(
15131998
     let unit_entry = state.units.get(&unit);
15141999
 
15152000
     if !exist.is_null() {
1516
-        unsafe { *exist = unit_entry.is_some() as i32; }
2001
+        unsafe {
2002
+            *exist = unit_entry.is_some() as i32;
2003
+        }
15172004
     }
15182005
     if !opened.is_null() {
1519
-        unsafe { *opened = unit_entry.is_some() as i32; }
2006
+        unsafe {
2007
+            *opened = unit_entry.is_some() as i32;
2008
+        }
15202009
     }
15212010
 
15222011
     if let Some(u) = unit_entry {
15232012
         write_inquire_string(name_buf, name_buf_len, &u.filename);
1524
-        write_unit_properties(u, access_buf, access_buf_len, form_buf, form_buf_len,
1525
-                              action_buf, action_buf_len, recl_out);
2013
+        write_unit_properties(
2014
+            u,
2015
+            access_buf,
2016
+            access_buf_len,
2017
+            form_buf,
2018
+            form_buf_len,
2019
+            action_buf,
2020
+            action_buf_len,
2021
+            recl_out,
2022
+        );
15262023
 
15272024
         if !size_out.is_null() {
15282025
             let sz = if !u.filename.is_empty() {
1529
-                std::fs::metadata(&u.filename).map(|m| m.len() as i64).unwrap_or(-1)
1530
-            } else { -1 };
1531
-            unsafe { *size_out = sz; }
2026
+                std::fs::metadata(&u.filename)
2027
+                    .map(|m| m.len() as i64)
2028
+                    .unwrap_or(-1)
2029
+            } else {
2030
+                -1
2031
+            };
2032
+            unsafe {
2033
+                *size_out = sz;
2034
+            }
15322035
         }
15332036
     } else {
15342037
         write_inquire_string(name_buf, name_buf_len, "");
15352038
         write_inquire_string(access_buf, access_buf_len, "UNDEFINED");
15362039
         write_inquire_string(form_buf, form_buf_len, "UNDEFINED");
15372040
         write_inquire_string(action_buf, action_buf_len, "UNDEFINED");
1538
-        if !size_out.is_null() { unsafe { *size_out = -1; } }
2041
+        if !size_out.is_null() {
2042
+            unsafe {
2043
+                *size_out = -1;
2044
+            }
2045
+        }
15392046
     }
15402047
 
15412048
     if !iostat.is_null() {
1542
-        unsafe { *iostat = 0; }
2049
+        unsafe {
2050
+            *iostat = 0;
2051
+        }
15432052
     }
15442053
 }
15452054
 
15462055
 /// Write ACCESS, FORM, ACTION, RECL for a connected unit.
15472056
 fn write_unit_properties(
15482057
     u: &Unit,
1549
-    access_buf: *mut u8, access_buf_len: i64,
1550
-    form_buf: *mut u8, form_buf_len: i64,
1551
-    action_buf: *mut u8, action_buf_len: i64,
2058
+    access_buf: *mut u8,
2059
+    access_buf_len: i64,
2060
+    form_buf: *mut u8,
2061
+    form_buf_len: i64,
2062
+    action_buf: *mut u8,
2063
+    action_buf_len: i64,
15522064
     recl_out: *mut i64,
15532065
 ) {
15542066
     let access_str = match u.access {
@@ -1572,7 +2084,9 @@ fn write_unit_properties(
15722084
     write_inquire_string(action_buf, action_buf_len, action_str);
15732085
 
15742086
     if !recl_out.is_null() {
1575
-        unsafe { *recl_out = u.recl.unwrap_or(-1); }
2087
+        unsafe {
2088
+            *recl_out = u.recl.unwrap_or(-1);
2089
+        }
15762090
     }
15772091
 }
15782092
 
@@ -1584,10 +2098,18 @@ pub extern "C" fn afs_flush(unit: i32, iostat: *mut i32) {
15842098
     let mut state = io_state().lock().unwrap_or_else(|e| e.into_inner());
15852099
     if let Some(u) = state.get_unit(unit) {
15862100
         match u.flush() {
1587
-            Ok(()) => { if !iostat.is_null() { unsafe { *iostat = 0; } } }
2101
+            Ok(()) => {
2102
+                if !iostat.is_null() {
2103
+                    unsafe {
2104
+                        *iostat = 0;
2105
+                    }
2106
+                }
2107
+            }
15882108
             Err(e) => {
15892109
                 if !iostat.is_null() {
1590
-                    unsafe { *iostat = e.raw_os_error().unwrap_or(1); }
2110
+                    unsafe {
2111
+                        *iostat = e.raw_os_error().unwrap_or(1);
2112
+                    }
15912113
                 }
15922114
             }
15932115
         }
@@ -1616,7 +2138,11 @@ pub extern "C" fn afs_rewind(unit: i32, iostat: *mut i32) {
16162138
         }
16172139
         // Clear stale read tokens so subsequent reads come from file start.
16182140
         u.read_tokens.clear();
1619
-        if !iostat.is_null() { unsafe { *iostat = 0; } }
2141
+        if !iostat.is_null() {
2142
+            unsafe {
2143
+                *iostat = 0;
2144
+            }
2145
+        }
16202146
     }
16212147
 }
16222148
 
@@ -1649,8 +2175,8 @@ pub extern "C" fn afs_io_finalize() {
16492175
 //   afs_fmt_push_int(val) / afs_fmt_push_int128(&val) / afs_fmt_push_real(val) / ...
16502176
 //   afs_fmt_end()
16512177
 
1652
-use std::cell::RefCell;
16532178
 use crate::format::{parse_format, FormatDesc, FormatEngine, IoValue};
2179
+use std::cell::RefCell;
16542180
 
16552181
 enum FmtSink {
16562182
     Unit(i32),
@@ -1857,7 +2383,10 @@ fn extract_nth_formatted_field(
18572383
 ) -> Option<(FormatDesc, String)> {
18582384
     for desc in descs {
18592385
         match desc {
1860
-            FormatDesc::Group { repeat, descriptors } => {
2386
+            FormatDesc::Group {
2387
+                repeat,
2388
+                descriptors,
2389
+            } => {
18612390
                 for _ in 0..*repeat {
18622391
                     if let Some(found) = extract_nth_formatted_field(
18632392
                         descriptors,
@@ -1970,20 +2499,42 @@ pub extern "C" fn afs_fmt_read_int(
19702499
     match formatted_read_record_for_unit(unit, data_index)
19712500
         .and_then(|line| parse_nth_formatted_record(line.as_bytes(), fmt_str, fmt_len, data_index))
19722501
     {
1973
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i32>() {
1974
-            Ok(v) => {
1975
-                if !val.is_null() { unsafe { *val = v; } }
1976
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
1977
-            }
1978
-            Err(_) => {
1979
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2502
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2503
+            match field.trim().replace(',', "").parse::<i32>() {
2504
+                Ok(v) => {
2505
+                    if !val.is_null() {
2506
+                        unsafe {
2507
+                            *val = v;
2508
+                        }
2509
+                    }
2510
+                    if !iostat.is_null() {
2511
+                        unsafe {
2512
+                            *iostat = 0;
2513
+                        }
2514
+                    }
2515
+                }
2516
+                Err(_) => {
2517
+                    if !iostat.is_null() {
2518
+                        unsafe {
2519
+                            *iostat = 1;
2520
+                        }
2521
+                    }
2522
+                }
19802523
             }
1981
-        },
2524
+        }
19822525
         Ok(_) => {
1983
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2526
+            if !iostat.is_null() {
2527
+                unsafe {
2528
+                    *iostat = 1;
2529
+                }
2530
+            }
19842531
         }
19852532
         Err(code) => {
1986
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2533
+            if !iostat.is_null() {
2534
+                unsafe {
2535
+                    *iostat = code;
2536
+                }
2537
+            }
19872538
         }
19882539
     }
19892540
 }
@@ -2000,20 +2551,42 @@ pub extern "C" fn afs_fmt_read_int64(
20002551
     match formatted_read_record_for_unit(unit, data_index)
20012552
         .and_then(|line| parse_nth_formatted_record(line.as_bytes(), fmt_str, fmt_len, data_index))
20022553
     {
2003
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i64>() {
2004
-            Ok(v) => {
2005
-                if !val.is_null() { unsafe { *val = v; } }
2006
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
2007
-            }
2008
-            Err(_) => {
2009
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2554
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2555
+            match field.trim().replace(',', "").parse::<i64>() {
2556
+                Ok(v) => {
2557
+                    if !val.is_null() {
2558
+                        unsafe {
2559
+                            *val = v;
2560
+                        }
2561
+                    }
2562
+                    if !iostat.is_null() {
2563
+                        unsafe {
2564
+                            *iostat = 0;
2565
+                        }
2566
+                    }
2567
+                }
2568
+                Err(_) => {
2569
+                    if !iostat.is_null() {
2570
+                        unsafe {
2571
+                            *iostat = 1;
2572
+                        }
2573
+                    }
2574
+                }
20102575
             }
2011
-        },
2576
+        }
20122577
         Ok(_) => {
2013
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2578
+            if !iostat.is_null() {
2579
+                unsafe {
2580
+                    *iostat = 1;
2581
+                }
2582
+            }
20142583
         }
20152584
         Err(code) => {
2016
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2585
+            if !iostat.is_null() {
2586
+                unsafe {
2587
+                    *iostat = code;
2588
+                }
2589
+            }
20172590
         }
20182591
     }
20192592
 }
@@ -2030,20 +2603,38 @@ pub extern "C" fn afs_fmt_read_int128(
20302603
     match formatted_read_record_for_unit(unit, data_index)
20312604
         .and_then(|line| parse_nth_formatted_record(line.as_bytes(), fmt_str, fmt_len, data_index))
20322605
     {
2033
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i128>() {
2034
-            Ok(v) => {
2035
-                write_i128_ptr(val, v);
2036
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
2037
-            }
2038
-            Err(_) => {
2039
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2606
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2607
+            match field.trim().replace(',', "").parse::<i128>() {
2608
+                Ok(v) => {
2609
+                    write_i128_ptr(val, v);
2610
+                    if !iostat.is_null() {
2611
+                        unsafe {
2612
+                            *iostat = 0;
2613
+                        }
2614
+                    }
2615
+                }
2616
+                Err(_) => {
2617
+                    if !iostat.is_null() {
2618
+                        unsafe {
2619
+                            *iostat = 1;
2620
+                        }
2621
+                    }
2622
+                }
20402623
             }
2041
-        },
2624
+        }
20422625
         Ok(_) => {
2043
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2626
+            if !iostat.is_null() {
2627
+                unsafe {
2628
+                    *iostat = 1;
2629
+                }
2630
+            }
20442631
         }
20452632
         Err(code) => {
2046
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2633
+            if !iostat.is_null() {
2634
+                unsafe {
2635
+                    *iostat = code;
2636
+                }
2637
+            }
20472638
         }
20482639
     }
20492640
 }
@@ -2067,22 +2658,46 @@ pub extern "C" fn afs_fmt_read_real(
20672658
         | Ok((FormatDesc::RealEX { .. }, field))
20682659
         | Ok((FormatDesc::RealD { .. }, field))
20692660
         | Ok((FormatDesc::RealG { .. }, field)) => {
2070
-            let normalized = field.trim().replace('d', "e").replace('D', "E").replace(',', "");
2661
+            let normalized = field
2662
+                .trim()
2663
+                .replace('d', "e")
2664
+                .replace('D', "E")
2665
+                .replace(',', "");
20712666
             match normalized.parse::<f64>() {
20722667
                 Ok(v) => {
2073
-                    if !val.is_null() { unsafe { *val = v; } }
2074
-                    if !iostat.is_null() { unsafe { *iostat = 0; } }
2668
+                    if !val.is_null() {
2669
+                        unsafe {
2670
+                            *val = v;
2671
+                        }
2672
+                    }
2673
+                    if !iostat.is_null() {
2674
+                        unsafe {
2675
+                            *iostat = 0;
2676
+                        }
2677
+                    }
20752678
                 }
20762679
                 Err(_) => {
2077
-                    if !iostat.is_null() { unsafe { *iostat = 1; } }
2680
+                    if !iostat.is_null() {
2681
+                        unsafe {
2682
+                            *iostat = 1;
2683
+                        }
2684
+                    }
20782685
                 }
20792686
             }
20802687
         }
20812688
         Ok(_) => {
2082
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2689
+            if !iostat.is_null() {
2690
+                unsafe {
2691
+                    *iostat = 1;
2692
+                }
2693
+            }
20832694
         }
20842695
         Err(code) => {
2085
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2696
+            if !iostat.is_null() {
2697
+                unsafe {
2698
+                    *iostat = code;
2699
+                }
2700
+            }
20862701
         }
20872702
     }
20882703
 }
@@ -2098,20 +2713,42 @@ pub extern "C" fn afs_fmt_read_int_internal(
20982713
     iostat: *mut i32,
20992714
 ) {
21002715
     match parse_nth_formatted_internal_field(buf, buf_len, fmt_str, fmt_len, data_index) {
2101
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i32>() {
2102
-            Ok(v) => {
2103
-                if !val.is_null() { unsafe { *val = v; } }
2104
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
2105
-            }
2106
-            Err(_) => {
2107
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2716
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2717
+            match field.trim().replace(',', "").parse::<i32>() {
2718
+                Ok(v) => {
2719
+                    if !val.is_null() {
2720
+                        unsafe {
2721
+                            *val = v;
2722
+                        }
2723
+                    }
2724
+                    if !iostat.is_null() {
2725
+                        unsafe {
2726
+                            *iostat = 0;
2727
+                        }
2728
+                    }
2729
+                }
2730
+                Err(_) => {
2731
+                    if !iostat.is_null() {
2732
+                        unsafe {
2733
+                            *iostat = 1;
2734
+                        }
2735
+                    }
2736
+                }
21082737
             }
2109
-        },
2738
+        }
21102739
         Ok(_) => {
2111
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2740
+            if !iostat.is_null() {
2741
+                unsafe {
2742
+                    *iostat = 1;
2743
+                }
2744
+            }
21122745
         }
21132746
         Err(code) => {
2114
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2747
+            if !iostat.is_null() {
2748
+                unsafe {
2749
+                    *iostat = code;
2750
+                }
2751
+            }
21152752
         }
21162753
     }
21172754
 }
@@ -2127,20 +2764,42 @@ pub extern "C" fn afs_fmt_read_int64_internal(
21272764
     iostat: *mut i32,
21282765
 ) {
21292766
     match parse_nth_formatted_internal_field(buf, buf_len, fmt_str, fmt_len, data_index) {
2130
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i64>() {
2131
-            Ok(v) => {
2132
-                if !val.is_null() { unsafe { *val = v; } }
2133
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
2134
-            }
2135
-            Err(_) => {
2136
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2767
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2768
+            match field.trim().replace(',', "").parse::<i64>() {
2769
+                Ok(v) => {
2770
+                    if !val.is_null() {
2771
+                        unsafe {
2772
+                            *val = v;
2773
+                        }
2774
+                    }
2775
+                    if !iostat.is_null() {
2776
+                        unsafe {
2777
+                            *iostat = 0;
2778
+                        }
2779
+                    }
2780
+                }
2781
+                Err(_) => {
2782
+                    if !iostat.is_null() {
2783
+                        unsafe {
2784
+                            *iostat = 1;
2785
+                        }
2786
+                    }
2787
+                }
21372788
             }
2138
-        },
2789
+        }
21392790
         Ok(_) => {
2140
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2791
+            if !iostat.is_null() {
2792
+                unsafe {
2793
+                    *iostat = 1;
2794
+                }
2795
+            }
21412796
         }
21422797
         Err(code) => {
2143
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2798
+            if !iostat.is_null() {
2799
+                unsafe {
2800
+                    *iostat = code;
2801
+                }
2802
+            }
21442803
         }
21452804
     }
21462805
 }
@@ -2156,20 +2815,38 @@ pub extern "C" fn afs_fmt_read_int128_internal(
21562815
     iostat: *mut i32,
21572816
 ) {
21582817
     match parse_nth_formatted_internal_field(buf, buf_len, fmt_str, fmt_len, data_index) {
2159
-        Ok((FormatDesc::IntegerI { .. }, field)) => match field.trim().replace(',', "").parse::<i128>() {
2160
-            Ok(v) => {
2161
-                write_i128_ptr(val, v);
2162
-                if !iostat.is_null() { unsafe { *iostat = 0; } }
2163
-            }
2164
-            Err(_) => {
2165
-                if !iostat.is_null() { unsafe { *iostat = 1; } }
2818
+        Ok((FormatDesc::IntegerI { .. }, field)) => {
2819
+            match field.trim().replace(',', "").parse::<i128>() {
2820
+                Ok(v) => {
2821
+                    write_i128_ptr(val, v);
2822
+                    if !iostat.is_null() {
2823
+                        unsafe {
2824
+                            *iostat = 0;
2825
+                        }
2826
+                    }
2827
+                }
2828
+                Err(_) => {
2829
+                    if !iostat.is_null() {
2830
+                        unsafe {
2831
+                            *iostat = 1;
2832
+                        }
2833
+                    }
2834
+                }
21662835
             }
2167
-        },
2836
+        }
21682837
         Ok(_) => {
2169
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2838
+            if !iostat.is_null() {
2839
+                unsafe {
2840
+                    *iostat = 1;
2841
+                }
2842
+            }
21702843
         }
21712844
         Err(code) => {
2172
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2845
+            if !iostat.is_null() {
2846
+                unsafe {
2847
+                    *iostat = code;
2848
+                }
2849
+            }
21732850
         }
21742851
     }
21752852
 }
@@ -2192,22 +2869,46 @@ pub extern "C" fn afs_fmt_read_real_internal(
21922869
         | Ok((FormatDesc::RealEX { .. }, field))
21932870
         | Ok((FormatDesc::RealD { .. }, field))
21942871
         | Ok((FormatDesc::RealG { .. }, field)) => {
2195
-            let normalized = field.trim().replace('d', "e").replace('D', "E").replace(',', "");
2872
+            let normalized = field
2873
+                .trim()
2874
+                .replace('d', "e")
2875
+                .replace('D', "E")
2876
+                .replace(',', "");
21962877
             match normalized.parse::<f64>() {
21972878
                 Ok(v) => {
2198
-                    if !val.is_null() { unsafe { *val = v; } }
2199
-                    if !iostat.is_null() { unsafe { *iostat = 0; } }
2879
+                    if !val.is_null() {
2880
+                        unsafe {
2881
+                            *val = v;
2882
+                        }
2883
+                    }
2884
+                    if !iostat.is_null() {
2885
+                        unsafe {
2886
+                            *iostat = 0;
2887
+                        }
2888
+                    }
22002889
                 }
22012890
                 Err(_) => {
2202
-                    if !iostat.is_null() { unsafe { *iostat = 1; } }
2891
+                    if !iostat.is_null() {
2892
+                        unsafe {
2893
+                            *iostat = 1;
2894
+                        }
2895
+                    }
22032896
                 }
22042897
             }
22052898
         }
22062899
         Ok(_) => {
2207
-            if !iostat.is_null() { unsafe { *iostat = 1; } }
2900
+            if !iostat.is_null() {
2901
+                unsafe {
2902
+                    *iostat = 1;
2903
+                }
2904
+            }
22082905
         }
22092906
         Err(code) => {
2210
-            if !iostat.is_null() { unsafe { *iostat = code; } }
2907
+            if !iostat.is_null() {
2908
+                unsafe {
2909
+                    *iostat = code;
2910
+                }
2911
+            }
22112912
         }
22122913
     }
22132914
 }
@@ -2245,9 +2946,12 @@ mod tests {
22452946
         let path = "/tmp/afs_write_i128_test.dat";
22462947
         afs_open_simple(
22472948
             97,
2248
-            path.as_ptr(), path.len() as i64,
2249
-            "replace".as_ptr(), 7,
2250
-            std::ptr::null(), 0,
2949
+            path.as_ptr(),
2950
+            path.len() as i64,
2951
+            "replace".as_ptr(),
2952
+            7,
2953
+            std::ptr::null(),
2954
+            0,
22512955
         );
22522956
 
22532957
         afs_write_int128(97, 170141183460469231731687303715884105727i128);
@@ -2269,9 +2973,12 @@ mod tests {
22692973
 
22702974
         afs_open_simple(
22712975
             95,
2272
-            path.as_ptr(), path.len() as i64,
2273
-            "old".as_ptr(), 3,
2274
-            "read".as_ptr(), 4,
2976
+            path.as_ptr(),
2977
+            path.len() as i64,
2978
+            "old".as_ptr(),
2979
+            3,
2980
+            "read".as_ptr(),
2981
+            4,
22752982
         );
22762983
 
22772984
         let mut value = 0i128;
@@ -2335,13 +3042,7 @@ mod tests {
23353042
         let ptr = unsafe { raw.as_mut_ptr().add(1) as *mut i128 };
23363043
         let mut iostat = -99i32;
23373044
 
2338
-        afs_read_internal_int128(
2339
-            buf.as_ptr(),
2340
-            buf.len() as i64,
2341
-            &mut pos,
2342
-            ptr,
2343
-            &mut iostat,
2344
-        );
3045
+        afs_read_internal_int128(buf.as_ptr(), buf.len() as i64, &mut pos, ptr, &mut iostat);
23453046
 
23463047
         assert_eq!(iostat, 0, "expected internal i128 read to succeed");
23473048
         let value = unsafe { std::ptr::read_unaligned(ptr) };
@@ -2353,9 +3054,12 @@ mod tests {
23533054
         let path = "/tmp/afs_fmt_test.dat";
23543055
         afs_open_simple(
23553056
             99,
2356
-            path.as_ptr(), path.len() as i64,
2357
-            "replace".as_ptr(), 7,
2358
-            std::ptr::null(), 0,
3057
+            path.as_ptr(),
3058
+            path.len() as i64,
3059
+            "replace".as_ptr(),
3060
+            7,
3061
+            std::ptr::null(),
3062
+            0,
23593063
         );
23603064
 
23613065
         afs_fmt_begin(99, "(I5, F8.2)".as_ptr(), 10);
@@ -2376,9 +3080,12 @@ mod tests {
23763080
         let wide = 170141183460469231731687303715884105727i128;
23773081
         afs_open_simple(
23783082
             96,
2379
-            path.as_ptr(), path.len() as i64,
2380
-            "replace".as_ptr(), 7,
2381
-            std::ptr::null(), 0,
3083
+            path.as_ptr(),
3084
+            path.len() as i64,
3085
+            "replace".as_ptr(),
3086
+            7,
3087
+            std::ptr::null(),
3088
+            0,
23823089
         );
23833090
 
23843091
         afs_fmt_begin(96, "(I40)".as_ptr(), 5);
@@ -2404,7 +3111,12 @@ mod tests {
24043111
 
24053112
         unsafe { std::ptr::write_unaligned(ptr, wide) };
24063113
 
2407
-        afs_fmt_begin_internal(rendered.as_mut_ptr(), rendered.len() as i64, "(I40)".as_ptr(), 5);
3114
+        afs_fmt_begin_internal(
3115
+            rendered.as_mut_ptr(),
3116
+            rendered.len() as i64,
3117
+            "(I40)".as_ptr(),
3118
+            5,
3119
+        );
24083120
         afs_fmt_push_int128(ptr);
24093121
         afs_fmt_end(0);
24103122
 
@@ -2453,7 +3165,10 @@ mod tests {
24533165
             &mut iostat,
24543166
         );
24553167
 
2456
-        assert_eq!(iostat, 0, "expected formatted internal i128 read to succeed");
3168
+        assert_eq!(
3169
+            iostat, 0,
3170
+            "expected formatted internal i128 read to succeed"
3171
+        );
24573172
         assert_eq!(value, 170141183460469231731687303715884105727i128);
24583173
     }
24593174
 
@@ -2474,7 +3189,10 @@ mod tests {
24743189
             &mut iostat,
24753190
         );
24763191
 
2477
-        assert_eq!(iostat, 0, "expected formatted internal i128 read to succeed");
3192
+        assert_eq!(
3193
+            iostat, 0,
3194
+            "expected formatted internal i128 read to succeed"
3195
+        );
24783196
         let value = unsafe { std::ptr::read_unaligned(ptr) };
24793197
         assert_eq!(value, 170141183460469231731687303715884105727i128);
24803198
     }
@@ -2518,9 +3236,12 @@ mod tests {
25183236
 
25193237
         afs_open_simple(
25203238
             94,
2521
-            path.as_ptr(), path.len() as i64,
2522
-            "old".as_ptr(), 3,
2523
-            "read".as_ptr(), 4,
3239
+            path.as_ptr(),
3240
+            path.len() as i64,
3241
+            "old".as_ptr(),
3242
+            3,
3243
+            "read".as_ptr(),
3244
+            4,
25243245
         );
25253246
 
25263247
         let mut value = 0i128;
@@ -2539,9 +3260,12 @@ mod tests {
25393260
 
25403261
         afs_open_simple(
25413262
             93,
2542
-            path.as_ptr(), path.len() as i64,
2543
-            "old".as_ptr(), 3,
2544
-            "read".as_ptr(), 4,
3263
+            path.as_ptr(),
3264
+            path.len() as i64,
3265
+            "old".as_ptr(),
3266
+            3,
3267
+            "read".as_ptr(),
3268
+            4,
25453269
         );
25463270
 
25473271
         let mut first = 0i128;
@@ -2569,9 +3293,12 @@ mod tests {
25693293
 
25703294
         afs_open_simple(
25713295
             92,
2572
-            path.as_ptr(), path.len() as i64,
2573
-            "old".as_ptr(), 3,
2574
-            "readwrite".as_ptr(), 9,
3296
+            path.as_ptr(),
3297
+            path.len() as i64,
3298
+            "old".as_ptr(),
3299
+            3,
3300
+            "readwrite".as_ptr(),
3301
+            9,
25753302
         );
25763303
 
25773304
         let mut first = 0i128;
@@ -2579,12 +3306,18 @@ mod tests {
25793306
         let mut iostat = -99i32;
25803307
 
25813308
         afs_fmt_read_int128(92, "(I40)".as_ptr(), 5, 0, &mut first, &mut iostat);
2582
-        assert_eq!(iostat, 0, "expected first formatted readwrite-unit read to succeed");
3309
+        assert_eq!(
3310
+            iostat, 0,
3311
+            "expected first formatted readwrite-unit read to succeed"
3312
+        );
25833313
 
25843314
         afs_fmt_read_int128(92, "(I40)".as_ptr(), 5, 0, &mut second, &mut iostat);
25853315
         afs_close(92, std::ptr::null_mut());
25863316
 
2587
-        assert_eq!(iostat, 0, "expected second formatted readwrite-unit read to succeed");
3317
+        assert_eq!(
3318
+            iostat, 0,
3319
+            "expected second formatted readwrite-unit read to succeed"
3320
+        );
25883321
         assert_eq!(first, 170141183460469231731687303715884105727i128);
25893322
         assert_eq!(second, -170141183460469231731687303715884105727i128);
25903323
     }
@@ -2594,9 +3327,12 @@ mod tests {
25943327
         let path = "/tmp/afs_fmt_noadv_test.dat";
25953328
         afs_open_simple(
25963329
             98,
2597
-            path.as_ptr(), path.len() as i64,
2598
-            "replace".as_ptr(), 7,
2599
-            std::ptr::null(), 0,
3330
+            path.as_ptr(),
3331
+            path.len() as i64,
3332
+            "replace".as_ptr(),
3333
+            7,
3334
+            std::ptr::null(),
3335
+            0,
26003336
         );
26013337
 
26023338
         afs_fmt_begin(98, "('hello')".as_ptr(), 9);
runtime/src/lib.rsmodified
17 lines changed — click to load
@@ -11,12 +11,12 @@
1111
 #![allow(clippy::not_unsafe_ptr_arg_deref)]
1212
 #![allow(clippy::missing_safety_doc)]
1313
 
14
-pub mod descriptor;
1514
 pub mod array;
16
-pub mod string;
15
+pub mod descriptor;
1716
 pub mod format;
18
-pub mod io_system;
19
-pub mod system;
2017
 mod io;
21
-mod mem;
18
+pub mod io_system;
2219
 mod lifecycle;
20
+mod mem;
21
+pub mod string;
22
+pub mod system;
runtime/src/mem.rsmodified
44 lines changed — click to load
@@ -41,10 +41,7 @@ pub extern "C" fn afs_deallocate(ptr: *mut u8) {
4141
 /// Concatenate two strings. Returns a newly allocated string.
4242
 /// Caller is responsible for freeing the result.
4343
 #[no_mangle]
44
-pub extern "C" fn afs_string_concat(
45
-    a: *const u8, alen: i64,
46
-    b: *const u8, blen: i64,
47
-) -> *mut u8 {
44
+pub extern "C" fn afs_string_concat(a: *const u8, alen: i64, b: *const u8, blen: i64) -> *mut u8 {
4845
     let total = (alen + blen) as usize;
4946
     let result = afs_allocate(total as i64);
5047
     if !a.is_null() && alen > 0 {
@@ -59,10 +56,7 @@ pub extern "C" fn afs_string_concat(
5956
 /// Copy a string into a fixed-length buffer, padding with spaces.
6057
 /// Used for character assignment to fixed-length variables.
6158
 #[no_mangle]
62
-pub extern "C" fn afs_string_copy(
63
-    dest: *mut u8, dest_len: i64,
64
-    src: *const u8, src_len: i64,
65
-) {
59
+pub extern "C" fn afs_string_copy(dest: *mut u8, dest_len: i64, src: *const u8, src_len: i64) {
6660
     if dest.is_null() || dest_len <= 0 {
6761
         return;
6862
     }
@@ -81,15 +75,16 @@ pub extern "C" fn afs_string_copy(
8175
 /// Compare two strings lexicographically.
8276
 /// Returns negative, zero, or positive (like strcmp but for counted strings).
8377
 #[no_mangle]
84
-pub extern "C" fn afs_string_compare(
85
-    a: *const u8, alen: i64,
86
-    b: *const u8, blen: i64,
87
-) -> i32 {
78
+pub extern "C" fn afs_string_compare(a: *const u8, alen: i64, b: *const u8, blen: i64) -> i32 {
8879
     let sa = if !a.is_null() && alen > 0 {
8980
         unsafe { std::slice::from_raw_parts(a, alen as usize) }
90
-    } else { &[] };
81
+    } else {
82
+        &[]
83
+    };
9184
     let sb = if !b.is_null() && blen > 0 {
9285
         unsafe { std::slice::from_raw_parts(b, blen as usize) }
93
-    } else { &[] };
86
+    } else {
87
+        &[]
88
+    };
9489
     sa.cmp(sb) as i32
9590
 }
runtime/src/system.rsmodified
370 lines changed — click to load
@@ -10,27 +10,48 @@ pub extern "C" fn afs_system_clock(count: *mut i64, count_rate: *mut i64, count_
1010
         .unwrap_or_default();
1111
     let nanos = now.as_nanos() as i64;
1212
 
13
-    if !count.is_null() { unsafe { *count = nanos; } }
14
-    if !count_rate.is_null() { unsafe { *count_rate = 1_000_000_000; } }
15
-    if !count_max.is_null() { unsafe { *count_max = i64::MAX; } }
13
+    if !count.is_null() {
14
+        unsafe {
15
+            *count = nanos;
16
+        }
17
+    }
18
+    if !count_rate.is_null() {
19
+        unsafe {
20
+            *count_rate = 1_000_000_000;
21
+        }
22
+    }
23
+    if !count_max.is_null() {
24
+        unsafe {
25
+            *count_max = i64::MAX;
26
+        }
27
+    }
1628
 }
1729
 
1830
 /// CPU_TIME: returns processor time in seconds.
1931
 #[no_mangle]
2032
 pub extern "C" fn afs_cpu_time(time: *mut f64) {
21
-    if time.is_null() { return; }
22
-    extern "C" { fn clock() -> i64; }
33
+    if time.is_null() {
34
+        return;
35
+    }
36
+    extern "C" {
37
+        fn clock() -> i64;
38
+    }
2339
     const CLOCKS_PER_SEC: i64 = 1_000_000; // POSIX value on macOS
2440
     let ticks = unsafe { clock() };
25
-    unsafe { *time = ticks as f64 / CLOCKS_PER_SEC as f64; }
41
+    unsafe {
42
+        *time = ticks as f64 / CLOCKS_PER_SEC as f64;
43
+    }
2644
 }
2745
 
2846
 /// DATE_AND_TIME: returns date, time, timezone, and 8-element values array.
2947
 #[no_mangle]
3048
 pub extern "C" fn afs_date_and_time(
31
-    date_buf: *mut u8, date_len: i64,
32
-    time_buf: *mut u8, time_len: i64,
33
-    zone_buf: *mut u8, zone_len: i64,
49
+    date_buf: *mut u8,
50
+    date_len: i64,
51
+    time_buf: *mut u8,
52
+    time_len: i64,
53
+    zone_buf: *mut u8,
54
+    zone_len: i64,
3455
     values: *mut i32,
3556
 ) {
3657
     use std::time::SystemTime;
@@ -43,10 +64,16 @@ pub extern "C" fn afs_date_and_time(
4364
     // Use POSIX localtime_r to decompose.
4465
     #[repr(C)]
4566
     struct Tm {
46
-        tm_sec: i32, tm_min: i32, tm_hour: i32, tm_mday: i32,
47
-        tm_mon: i32, tm_year: i32, tm_wday: i32, tm_yday: i32,
67
+        tm_sec: i32,
68
+        tm_min: i32,
69
+        tm_hour: i32,
70
+        tm_mday: i32,
71
+        tm_mon: i32,
72
+        tm_year: i32,
73
+        tm_wday: i32,
74
+        tm_yday: i32,
4875
         tm_isdst: i32,
49
-        tm_gmtoff: i64,  // macOS: long (8 bytes on ARM64)
76
+        tm_gmtoff: i64, // macOS: long (8 bytes on ARM64)
5077
         tm_zone: *const u8,
5178
     }
5279
     extern "C" {
@@ -54,7 +81,9 @@ pub extern "C" fn afs_date_and_time(
5481
     }
5582
     let mut tm = unsafe { std::mem::zeroed::<Tm>() };
5683
     let time_t = secs;
57
-    unsafe { localtime_r(&time_t, &mut tm); }
84
+    unsafe {
85
+        localtime_r(&time_t, &mut tm);
86
+    }
5887
 
5988
     let year = tm.tm_year + 1900;
6089
     let month = tm.tm_mon + 1;
@@ -69,9 +98,13 @@ pub extern "C" fn afs_date_and_time(
6998
         let s = format!("{:04}{:02}{:02}", year, month, day);
7099
         let bytes = s.as_bytes();
71100
         let n = bytes.len().min(date_len as usize);
72
-        unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), date_buf, n); }
101
+        unsafe {
102
+            std::ptr::copy_nonoverlapping(bytes.as_ptr(), date_buf, n);
103
+        }
73104
         if n < date_len as usize {
74
-            unsafe { std::ptr::write_bytes(date_buf.add(n), b' ', date_len as usize - n); }
105
+            unsafe {
106
+                std::ptr::write_bytes(date_buf.add(n), b' ', date_len as usize - n);
107
+            }
75108
         }
76109
     }
77110
 
@@ -80,9 +113,13 @@ pub extern "C" fn afs_date_and_time(
80113
         let s = format!("{:02}{:02}{:02}.{:03}", hour, minute, second, millis);
81114
         let bytes = s.as_bytes();
82115
         let n = bytes.len().min(time_len as usize);
83
-        unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), time_buf, n); }
116
+        unsafe {
117
+            std::ptr::copy_nonoverlapping(bytes.as_ptr(), time_buf, n);
118
+        }
84119
         if n < time_len as usize {
85
-            unsafe { std::ptr::write_bytes(time_buf.add(n), b' ', time_len as usize - n); }
120
+            unsafe {
121
+                std::ptr::write_bytes(time_buf.add(n), b' ', time_len as usize - n);
122
+            }
86123
         }
87124
     }
88125
 
@@ -93,9 +130,13 @@ pub extern "C" fn afs_date_and_time(
93130
         let s = format!("{}{:02}{:02}", sign, abs_min / 60, abs_min % 60);
94131
         let bytes = s.as_bytes();
95132
         let n = bytes.len().min(zone_len as usize);
96
-        unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), zone_buf, n); }
133
+        unsafe {
134
+            std::ptr::copy_nonoverlapping(bytes.as_ptr(), zone_buf, n);
135
+        }
97136
         if n < zone_len as usize {
98
-            unsafe { std::ptr::write_bytes(zone_buf.add(n), b' ', zone_len as usize - n); }
137
+            unsafe {
138
+                std::ptr::write_bytes(zone_buf.add(n), b' ', zone_len as usize - n);
139
+            }
99140
         }
100141
     }
101142
 
@@ -124,14 +165,23 @@ pub extern "C" fn afs_command_argument_count() -> i32 {
124165
 #[no_mangle]
125166
 pub extern "C" fn afs_get_command_argument(
126167
     number: i32,
127
-    value: *mut u8, value_len: i64,
168
+    value: *mut u8,
169
+    value_len: i64,
128170
     length: *mut i32,
129171
     status: *mut i32,
130172
 ) {
131173
     let args: Vec<String> = std::env::args().collect();
132174
     if number < 0 || number as usize >= args.len() {
133
-        if !status.is_null() { unsafe { *status = 1; } }
134
-        if !length.is_null() { unsafe { *length = 0; } }
175
+        if !status.is_null() {
176
+            unsafe {
177
+                *status = 1;
178
+            }
179
+        }
180
+        if !length.is_null() {
181
+            unsafe {
182
+                *length = 0;
183
+            }
184
+        }
135185
         return;
136186
     }
137187
 
@@ -139,7 +189,9 @@ pub extern "C" fn afs_get_command_argument(
139189
     let bytes = arg.as_bytes();
140190
 
141191
     if !length.is_null() {
142
-        unsafe { *length = bytes.len() as i32; }
192
+        unsafe {
193
+            *length = bytes.len() as i32;
194
+        }
143195
     }
144196
 
145197
     if !value.is_null() && value_len > 0 {
@@ -152,20 +204,29 @@ pub extern "C" fn afs_get_command_argument(
152204
         }
153205
     }
154206
 
155
-    if !status.is_null() { unsafe { *status = 0; } }
207
+    if !status.is_null() {
208
+        unsafe {
209
+            *status = 0;
210
+        }
211
+    }
156212
 }
157213
 
158214
 /// GET_COMMAND: retrieve the full command line.
159215
 #[no_mangle]
160216
 pub extern "C" fn afs_get_command(
161
-    command: *mut u8, cmd_len: i64,
217
+    command: *mut u8,
218
+    cmd_len: i64,
162219
     length: *mut i32,
163220
     status: *mut i32,
164221
 ) {
165222
     let full: String = std::env::args().collect::<Vec<_>>().join(" ");
166223
     let bytes = full.as_bytes();
167224
 
168
-    if !length.is_null() { unsafe { *length = bytes.len() as i32; } }
225
+    if !length.is_null() {
226
+        unsafe {
227
+            *length = bytes.len() as i32;
228
+        }
229
+    }
169230
     if !command.is_null() && cmd_len > 0 {
170231
         let n = bytes.len().min(cmd_len as usize);
171232
         unsafe {
@@ -175,14 +236,20 @@ pub extern "C" fn afs_get_command(
175236
             }
176237
         }
177238
     }
178
-    if !status.is_null() { unsafe { *status = 0; } }
239
+    if !status.is_null() {
240
+        unsafe {
241
+            *status = 0;
242
+        }
243
+    }
179244
 }
180245
 
181246
 /// GET_ENVIRONMENT_VARIABLE: retrieve an environment variable by name.
182247
 #[no_mangle]
183248
 pub extern "C" fn afs_get_environment_variable(
184
-    name: *const u8, name_len: i64,
185
-    value: *mut u8, value_len: i64,
249
+    name: *const u8,
250
+    name_len: i64,
251
+    value: *mut u8,
252
+    value_len: i64,
186253
     length: *mut i32,
187254
     status: *mut i32,
188255
 ) {
@@ -190,14 +257,22 @@ pub extern "C" fn afs_get_environment_variable(
190257
         let slice = unsafe { std::slice::from_raw_parts(name, name_len as usize) };
191258
         String::from_utf8_lossy(slice).trim().to_string()
192259
     } else {
193
-        if !status.is_null() { unsafe { *status = 1; } }
260
+        if !status.is_null() {
261
+            unsafe {
262
+                *status = 1;
263
+            }
264
+        }
194265
         return;
195266
     };
196267
 
197268
     match std::env::var(&var_name) {
198269
         Ok(val) => {
199270
             let bytes = val.as_bytes();
200
-            if !length.is_null() { unsafe { *length = bytes.len() as i32; } }
271
+            if !length.is_null() {
272
+                unsafe {
273
+                    *length = bytes.len() as i32;
274
+                }
275
+            }
201276
             if !value.is_null() && value_len > 0 {
202277
                 let n = bytes.len().min(value_len as usize);
203278
                 unsafe {
@@ -207,11 +282,23 @@ pub extern "C" fn afs_get_environment_variable(
207282
                     }
208283
                 }
209284
             }
210
-            if !status.is_null() { unsafe { *status = 0; } }
285
+            if !status.is_null() {
286
+                unsafe {
287
+                    *status = 0;
288
+                }
289
+            }
211290
         }
212291
         Err(_) => {
213
-            if !length.is_null() { unsafe { *length = 0; } }
214
-            if !status.is_null() { unsafe { *status = 1; } }
292
+            if !length.is_null() {
293
+                unsafe {
294
+                    *length = 0;
295
+                }
296
+            }
297
+            if !status.is_null() {
298
+                unsafe {
299
+                    *status = 1;
300
+                }
301
+            }
215302
         }
216303
     }
217304
 }
@@ -219,7 +306,8 @@ pub extern "C" fn afs_get_environment_variable(
219306
 /// EXECUTE_COMMAND_LINE: run a shell command.
220307
 #[no_mangle]
221308
 pub extern "C" fn afs_execute_command_line(
222
-    command: *const u8, cmd_len: i64,
309
+    command: *const u8,
310
+    cmd_len: i64,
223311
     wait: i32,
224312
     exitstat: *mut i32,
225313
     cmdstat: *mut i32,
@@ -228,7 +316,11 @@ pub extern "C" fn afs_execute_command_line(
228316
         let slice = unsafe { std::slice::from_raw_parts(command, cmd_len as usize) };
229317
         String::from_utf8_lossy(slice).trim().to_string()
230318
     } else {
231
-        if !cmdstat.is_null() { unsafe { *cmdstat = 1; } }
319
+        if !cmdstat.is_null() {
320
+            unsafe {
321
+                *cmdstat = 1;
322
+            }
323
+        }
232324
         return;
233325
     };
234326
 
@@ -236,17 +328,41 @@ pub extern "C" fn afs_execute_command_line(
236328
     if wait != 0 {
237329
         match Command::new("sh").arg("-c").arg(&cmd).status() {
238330
             Ok(status) => {
239
-                if !exitstat.is_null() { unsafe { *exitstat = status.code().unwrap_or(-1); } }
240
-                if !cmdstat.is_null() { unsafe { *cmdstat = 0; } }
331
+                if !exitstat.is_null() {
332
+                    unsafe {
333
+                        *exitstat = status.code().unwrap_or(-1);
334
+                    }
335
+                }
336
+                if !cmdstat.is_null() {
337
+                    unsafe {
338
+                        *cmdstat = 0;
339
+                    }
340
+                }
241341
             }
242342
             Err(_) => {
243
-                if !cmdstat.is_null() { unsafe { *cmdstat = -1; } }
343
+                if !cmdstat.is_null() {
344
+                    unsafe {
345
+                        *cmdstat = -1;
346
+                    }
347
+                }
244348
             }
245349
         }
246350
     } else {
247351
         match Command::new("sh").arg("-c").arg(&cmd).spawn() {
248
-            Ok(_) => { if !cmdstat.is_null() { unsafe { *cmdstat = 0; } } }
249
-            Err(_) => { if !cmdstat.is_null() { unsafe { *cmdstat = -1; } } }
352
+            Ok(_) => {
353
+                if !cmdstat.is_null() {
354
+                    unsafe {
355
+                        *cmdstat = 0;
356
+                    }
357
+                }
358
+            }
359
+            Err(_) => {
360
+                if !cmdstat.is_null() {
361
+                    unsafe {
362
+                        *cmdstat = -1;
363
+                    }
364
+                }
365
+            }
250366
         }
251367
     }
252368
 }
@@ -260,12 +376,18 @@ thread_local! {
260376
 /// RANDOM_NUMBER: fill a scalar with a random value in [0, 1).
261377
 #[no_mangle]
262378
 pub extern "C" fn afs_random_number_f64(harvest: *mut f64) {
263
-    if harvest.is_null() { return; }
379
+    if harvest.is_null() {
380
+        return;
381
+    }
264382
     RNG_SEED.with(|s| {
265383
         let mut x = s.get();
266
-        x = x.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
384
+        x = x
385
+            .wrapping_mul(6364136223846793005)
386
+            .wrapping_add(1442695040888963407);
267387
         s.set(x);
268
-        unsafe { *harvest = (x >> 11) as f64 / (1u64 << 53) as f64; }
388
+        unsafe {
389
+            *harvest = (x >> 11) as f64 / (1u64 << 53) as f64;
390
+        }
269391
     });
270392
 }
271393
 
@@ -293,7 +415,9 @@ mod tests {
293415
         afs_system_clock(&mut c1, &mut rate, std::ptr::null_mut());
294416
         // Busy loop to ensure time passes.
295417
         let mut sum = 0u64;
296
-        for i in 0..100000 { sum = sum.wrapping_add(i); }
418
+        for i in 0..100000 {
419
+            sum = sum.wrapping_add(i);
420
+        }
297421
         let _ = sum;
298422
         afs_system_clock(&mut c2, std::ptr::null_mut(), std::ptr::null_mut());
299423
         assert!(c2 >= c1, "clock should not go backwards: {} vs {}", c1, c2);
src/ast/decl.rsmodified
106 lines changed — click to load
@@ -3,8 +3,8 @@
33
 //! Types, attributes, entity declarations, USE statements, IMPLICIT,
44
 //! derived type definitions, and legacy declaration forms.
55
 
6
-use super::Spanned;
76
 use super::expr::SpannedExpr;
7
+use super::Spanned;
88
 
99
 /// A spanned declaration.
1010
 pub type SpannedDecl = Spanned<Decl>;
@@ -26,18 +26,16 @@ pub enum Decl {
2626
 
2727
     /// `PUBLIC :: name1, name2` or `PRIVATE :: name1, name2` — sets
2828
     /// access on specific names.
29
-    AccessList { access: Attribute, names: Vec<String> },
29
+    AccessList {
30
+        access: Attribute,
31
+        names: Vec<String>,
32
+    },
3033
 
3134
     /// `implicit none` or `implicit none(type, external)`
32
-    ImplicitNone {
33
-        external: bool,
34
-        type_: bool,
35
-    },
35
+    ImplicitNone { external: bool, type_: bool },
3636
 
3737
     /// `implicit double precision (a-h, o-z)`
38
-    ImplicitStmt {
39
-        specs: Vec<ImplicitSpec>,
40
-    },
38
+    ImplicitStmt { specs: Vec<ImplicitSpec> },
4139
 
4240
     /// Derived type definition
4341
     DerivedTypeDef {
@@ -58,9 +56,7 @@ pub enum Decl {
5856
     },
5957
 
6058
     /// `parameter (pi = 3.14159, e = 2.71828)`
61
-    ParameterStmt {
62
-        pairs: Vec<(String, SpannedExpr)>,
63
-    },
59
+    ParameterStmt { pairs: Vec<(String, SpannedExpr)> },
6460
 
6561
     /// `common /block_name/ x, y, z`
6662
     CommonBlock {
@@ -69,14 +65,10 @@ pub enum Decl {
6965
     },
7066
 
7167
     /// `equivalence (a, b), (c, d)`
72
-    EquivalenceStmt {
73
-        groups: Vec<Vec<SpannedExpr>>,
74
-    },
68
+    EquivalenceStmt { groups: Vec<Vec<SpannedExpr>> },
7569
 
7670
     /// `data x /1.0/, y /2.0/`
77
-    DataStmt {
78
-        sets: Vec<DataSet>,
79
-    },
71
+    DataStmt { sets: Vec<DataSet> },
8072
 
8173
     /// `enum, bind(c)`
8274
     EnumDef {
@@ -130,8 +122,8 @@ pub struct CharSelector {
130122
 #[derive(Debug, Clone, PartialEq)]
131123
 pub enum LenSpec {
132124
     Expr(SpannedExpr),
133
-    Star,   // len=* (assumed length)
134
-    Colon,  // len=: (deferred length)
125
+    Star,  // len=* (assumed length)
126
+    Colon, // len=: (deferred length)
135127
 }
136128
 
137129
 // ---- Attributes ----
@@ -176,13 +168,9 @@ pub enum ArraySpec {
176168
         upper: SpannedExpr,
177169
     },
178170
     /// `(:)` — assumed shape (for dummy arguments)
179
-    AssumedShape {
180
-        lower: Option<SpannedExpr>,
181
-    },
171
+    AssumedShape { lower: Option<SpannedExpr> },
182172
     /// `(*)` — assumed size (last dimension only)
183
-    AssumedSize {
184
-        lower: Option<SpannedExpr>,
185
-    },
173
+    AssumedSize { lower: Option<SpannedExpr> },
186174
     /// `(:)` with allocatable/pointer — deferred shape
187175
     Deferred,
188176
     /// `(..)` — assumed rank (F2018)
@@ -196,9 +184,9 @@ pub enum ArraySpec {
196184
 pub struct EntityDecl {
197185
     pub name: String,
198186
     pub array_spec: Option<Vec<ArraySpec>>,
199
-    pub char_len: Option<LenSpec>,      // character entity-specific length
200
-    pub init: Option<SpannedExpr>,      // = expr
201
-    pub ptr_init: Option<SpannedExpr>,  // => expr
187
+    pub char_len: Option<LenSpec>, // character entity-specific length
188
+    pub init: Option<SpannedExpr>, // = expr
189
+    pub ptr_init: Option<SpannedExpr>, // => expr
202190
 }
203191
 
204192
 // ---- Derived type parts ----
@@ -217,8 +205,8 @@ pub enum TypeAttr {
217205
 #[derive(Debug, Clone, PartialEq)]
218206
 pub struct TypeBoundProc {
219207
     pub name: String,
220
-    pub binding: Option<String>,  // procedure :: name => binding
221
-    pub attrs: Vec<String>,       // pass, nopass, deferred, etc.
208
+    pub binding: Option<String>, // procedure :: name => binding
209
+    pub attrs: Vec<String>,      // pass, nopass, deferred, etc.
222210
     pub is_generic: bool,
223211
 }
224212
 
src/ast/expr.rsmodified
224 lines changed — click to load
@@ -3,50 +3,30 @@
33
 //! Represents all Fortran expression forms: literals, names, operators,
44
 //! function calls, array constructors, component access, and more.
55
 
6
-
76
 /// A Fortran expression.
87
 #[derive(Debug, Clone, PartialEq)]
98
 #[allow(clippy::enum_variant_names)]
109
 pub enum Expr {
1110
     // ---- Literals ----
12
-
1311
     /// Integer literal: `42`, `42_8`, `42_int64`
14
-    IntegerLiteral {
15
-        text: String,
16
-        kind: Option<String>,
17
-    },
12
+    IntegerLiteral { text: String, kind: Option<String> },
1813
     /// Real literal: `3.14`, `1.0d0`, `6.022e23`, `1.0_8`, `.5`, `5.`
19
-    RealLiteral {
20
-        text: String,
21
-        kind: Option<String>,
22
-    },
14
+    RealLiteral { text: String, kind: Option<String> },
2315
     /// String literal: `'hello'`, `"hello"`, `'it''s'`
24
-    StringLiteral {
25
-        value: String,
26
-        kind: Option<String>,
27
-    },
16
+    StringLiteral { value: String, kind: Option<String> },
2817
     /// Logical literal: `.true.`, `.false.`, `.true._4`
29
-    LogicalLiteral {
30
-        value: bool,
31
-        kind: Option<String>,
32
-    },
18
+    LogicalLiteral { value: bool, kind: Option<String> },
3319
     /// Complex literal: `(1.0, 2.0)`
3420
     ComplexLiteral {
3521
         real: Box<SpannedExpr>,
3622
         imag: Box<SpannedExpr>,
3723
     },
3824
     /// BOZ literal: `B'1010'`, `O'777'`, `Z'FF'`
39
-    BozLiteral {
40
-        text: String,
41
-        base: BozBase,
42
-    },
25
+    BozLiteral { text: String, base: BozBase },
4326
 
4427
     // ---- Names and access ----
45
-
4628
     /// Simple name (variable, function, type, etc.)
47
-    Name {
48
-        name: String,
49
-    },
29
+    Name { name: String },
5030
     /// Component access: `x%field`, `x%inner%deep`
5131
     ComponentAccess {
5232
         base: Box<SpannedExpr>,
@@ -54,7 +34,6 @@ pub enum Expr {
5434
     },
5535
 
5636
     // ---- Operations ----
57
-
5837
     /// Unary operation: `-x`, `.not. x`, `+x`
5938
     UnaryOp {
6039
         op: UnaryOp,
@@ -70,7 +49,6 @@ pub enum Expr {
7049
     // ---- Calls and subscripts ----
7150
     // Note: A(I) is ambiguous — could be array access, function call, or substring.
7251
     // The parser produces FunctionCall for all of them; sema disambiguates.
73
-
7452
     /// Function call or array access: `sin(x)`, `a(i,j)`, `s(1:5)`
7553
     FunctionCall {
7654
         callee: Box<SpannedExpr>,
@@ -78,19 +56,15 @@ pub enum Expr {
7856
     },
7957
 
8058
     // ---- Array constructors ----
81
-
8259
     /// Array constructor: `[1, 2, 3]` or `(/ 1, 2, 3 /)`
8360
     ArrayConstructor {
84
-        type_spec: Option<String>,  // [integer :: 1, 2, 3]
61
+        type_spec: Option<String>, // [integer :: 1, 2, 3]
8562
         values: Vec<AcValue>,
8663
     },
8764
 
8865
     // ---- Parenthesized ----
89
-
9066
     /// Parenthesized expression: `(x + y)`
91
-    ParenExpr {
92
-        inner: Box<SpannedExpr>,
93
-    },
67
+    ParenExpr { inner: Box<SpannedExpr> },
9468
 }
9569
 
9670
 /// An expression with source location.
@@ -104,7 +78,11 @@ impl SpannedExpr {
10478
             Expr::RealLiteral { text, .. } => text.clone(),
10579
             Expr::StringLiteral { value, .. } => format!("'{}'", value),
10680
             Expr::LogicalLiteral { value, .. } => {
107
-                if *value { ".true.".into() } else { ".false.".into() }
81
+                if *value {
82
+                    ".true.".into()
83
+                } else {
84
+                    ".false.".into()
85
+                }
10886
             }
10987
             Expr::ComplexLiteral { real, imag } => {
11088
                 format!("({}, {})", real.to_sexpr(), imag.to_sexpr())
@@ -121,27 +99,47 @@ impl SpannedExpr {
12199
                 format!("({} {} {})", left.to_sexpr(), op, right.to_sexpr())
122100
             }
123101
             Expr::FunctionCall { callee, args } => {
124
-                let args_str: Vec<String> = args.iter().map(|a| {
125
-                    if let Some(kw) = &a.keyword {
126
-                        format!("{}={}", kw, a.value.to_sexpr())
127
-                    } else {
128
-                        a.value.to_sexpr()
129
-                    }
130
-                }).collect();
102
+                let args_str: Vec<String> = args
103
+                    .iter()
104
+                    .map(|a| {
105
+                        if let Some(kw) = &a.keyword {
106
+                            format!("{}={}", kw, a.value.to_sexpr())
107
+                        } else {
108
+                            a.value.to_sexpr()
109
+                        }
110
+                    })
111
+                    .collect();
131112
                 format!("{}({})", callee.to_sexpr(), args_str.join(", "))
132113
             }
133114
             Expr::ArrayConstructor { values, type_spec } => {
134
-                let vals: Vec<String> = values.iter().map(|v| match v {
135
-                    AcValue::Expr(e) => e.to_sexpr(),
136
-                    AcValue::ImpliedDo(ido) => {
137
-                        let vals: Vec<String> = ido.values.iter().map(|v| match v {
138
-                            AcValue::Expr(e) => e.to_sexpr(),
139
-                            AcValue::ImpliedDo(_) => "(nested-implied-do)".into(),
140
-                        }).collect();
141
-                        let step_str = ido.step.as_ref().map_or(String::new(), |s| format!(", {}", s.to_sexpr()));
142
-                        format!("({}, {}={}, {}{})", vals.join(", "), ido.var, ido.start.to_sexpr(), ido.end.to_sexpr(), step_str)
143
-                    }
144
-                }).collect();
115
+                let vals: Vec<String> = values
116
+                    .iter()
117
+                    .map(|v| match v {
118
+                        AcValue::Expr(e) => e.to_sexpr(),
119
+                        AcValue::ImpliedDo(ido) => {
120
+                            let vals: Vec<String> = ido
121
+                                .values
122
+                                .iter()
123
+                                .map(|v| match v {
124
+                                    AcValue::Expr(e) => e.to_sexpr(),
125
+                                    AcValue::ImpliedDo(_) => "(nested-implied-do)".into(),
126
+                                })
127
+                                .collect();
128
+                            let step_str = ido
129
+                                .step
130
+                                .as_ref()
131
+                                .map_or(String::new(), |s| format!(", {}", s.to_sexpr()));
132
+                            format!(
133
+                                "({}, {}={}, {}{})",
134
+                                vals.join(", "),
135
+                                ido.var,
136
+                                ido.start.to_sexpr(),
137
+                                ido.end.to_sexpr(),
138
+                                step_str
139
+                            )
140
+                        }
141
+                    })
142
+                    .collect();
145143
                 if let Some(ts) = type_spec {
146144
                     format!("[{} :: {}]", ts, vals.join(", "))
147145
                 } else {
@@ -166,9 +164,9 @@ pub enum BozBase {
166164
 /// Unary operators.
167165
 #[derive(Debug, Clone, PartialEq, Eq)]
168166
 pub enum UnaryOp {
169
-    Plus,       // +
170
-    Minus,      // -
171
-    Not,        // .not.
167
+    Plus,            // +
168
+    Minus,           // -
169
+    Not,             // .not.
172170
     Defined(String), // .myop.
173171
 }
174172
 
@@ -187,28 +185,28 @@ impl std::fmt::Display for UnaryOp {
187185
 #[derive(Debug, Clone, PartialEq, Eq)]
188186
 pub enum BinaryOp {
189187
     // Arithmetic
190
-    Add,        // +
191
-    Sub,        // -
192
-    Mul,        // *
193
-    Div,        // /
194
-    Pow,        // **
188
+    Add, // +
189
+    Sub, // -
190
+    Mul, // *
191
+    Div, // /
192
+    Pow, // **
195193
 
196194
     // String
197
-    Concat,     // //
195
+    Concat, // //
198196
 
199197
     // Comparison
200
-    Eq,         // == or .eq.
201
-    Ne,         // /= or .ne.
202
-    Lt,         // < or .lt.
203
-    Le,         // <= or .le.
204
-    Gt,         // > or .gt.
205
-    Ge,         // >= or .ge.
198
+    Eq, // == or .eq.
199
+    Ne, // /= or .ne.
200
+    Lt, // < or .lt.
201
+    Le, // <= or .le.
202
+    Gt, // > or .gt.
203
+    Ge, // >= or .ge.
206204
 
207205
     // Logical
208
-    And,        // .and.
209
-    Or,         // .or.
210
-    Eqv,        // .eqv.
211
-    Neqv,       // .neqv.
206
+    And,  // .and.
207
+    Or,   // .or.
208
+    Eqv,  // .eqv.
209
+    Neqv, // .neqv.
212210
 
213211
     // User-defined
214212
     Defined(String), // .myop.
src/ast/mod.rsmodified
9 lines changed — click to load
@@ -4,8 +4,8 @@
44
 //! program units, and all Fortran constructs. Every node
55
 //! carries a Span for source location tracking.
66
 
7
-pub mod expr;
87
 pub mod decl;
8
+pub mod expr;
99
 pub mod stmt;
1010
 pub mod unit;
1111
 
src/ast/stmt.rsmodified
229 lines changed — click to load
@@ -2,9 +2,9 @@
22
 //!
33
 //! Control flow, assignments, calls, and all executable Fortran statements.
44
 
5
-use super::Spanned;
6
-use super::expr::SpannedExpr;
75
 use super::decl::SpannedDecl;
6
+use super::expr::SpannedExpr;
7
+use super::Spanned;
88
 
99
 /// A spanned statement.
1010
 pub type SpannedStmt = Spanned<Stmt>;
@@ -15,8 +15,14 @@ pub type SpannedStmt = Spanned<Stmt>;
1515
 #[allow(clippy::enum_variant_names)]
1616
 pub enum Stmt {
1717
     // ---- Assignment ----
18
-    Assignment { target: SpannedExpr, value: SpannedExpr },
19
-    PointerAssignment { target: SpannedExpr, value: SpannedExpr },
18
+    Assignment {
19
+        target: SpannedExpr,
20
+        value: SpannedExpr,
21
+    },
22
+    PointerAssignment {
23
+        target: SpannedExpr,
24
+        value: SpannedExpr,
25
+    },
2026
 
2127
     // ---- IF ----
2228
     IfConstruct {
@@ -26,7 +32,10 @@ pub enum Stmt {
2632
         else_ifs: Vec<(SpannedExpr, Vec<SpannedStmt>)>,
2733
         else_body: Option<Vec<SpannedStmt>>,
2834
     },
29
-    IfStmt { condition: SpannedExpr, action: Box<SpannedStmt> },
35
+    IfStmt {
36
+        condition: SpannedExpr,
37
+        action: Box<SpannedStmt>,
38
+    },
3039
 
3140
     // ---- DO loops ----
3241
     DoLoop {
@@ -72,14 +81,21 @@ pub enum Stmt {
7281
         body: Vec<SpannedStmt>,
7382
         elsewhere: Vec<(Option<SpannedExpr>, Vec<SpannedStmt>)>,
7483
     },
75
-    WhereStmt { mask: SpannedExpr, stmt: Box<SpannedStmt> },
84
+    WhereStmt {
85
+        mask: SpannedExpr,
86
+        stmt: Box<SpannedStmt>,
87
+    },
7688
     ForallConstruct {
7789
         name: Option<String>,
7890
         specs: Vec<ForallSpec>,
7991
         mask: Option<SpannedExpr>,
8092
         body: Vec<SpannedStmt>,
8193
     },
82
-    ForallStmt { specs: Vec<ForallSpec>, mask: Option<SpannedExpr>, stmt: Box<SpannedStmt> },
94
+    ForallStmt {
95
+        specs: Vec<ForallSpec>,
96
+        mask: Option<SpannedExpr>,
97
+        stmt: Box<SpannedStmt>,
98
+    },
8399
 
84100
     // ---- BLOCK / ASSOCIATE ----
85101
     Block {
@@ -99,43 +115,113 @@ pub enum Stmt {
99115
         decls: Vec<super::decl::SpannedDecl>,
100116
         body: Vec<SpannedStmt>,
101117
     },
102
-    Associate { name: Option<String>, assocs: Vec<(String, SpannedExpr)>, body: Vec<SpannedStmt> },
118
+    Associate {
119
+        name: Option<String>,
120
+        assocs: Vec<(String, SpannedExpr)>,
121
+        body: Vec<SpannedStmt>,
122
+    },
103123
 
104124
     // ---- Branch/transfer ----
105
-    Exit { name: Option<String> },
106
-    Cycle { name: Option<String> },
107
-    Stop { code: Option<SpannedExpr>, quiet: bool },
108
-    ErrorStop { code: Option<SpannedExpr>, quiet: bool },
109
-    Return { value: Option<SpannedExpr> },
110
-    Goto { label: u64 },
111
-    ComputedGoto { labels: Vec<u64>, selector: SpannedExpr },
112
-    ArithmeticIf { expr: SpannedExpr, neg: u64, zero: u64, pos: u64 },
125
+    Exit {
126
+        name: Option<String>,
127
+    },
128
+    Cycle {
129
+        name: Option<String>,
130
+    },
131
+    Stop {
132
+        code: Option<SpannedExpr>,
133
+        quiet: bool,
134
+    },
135
+    ErrorStop {
136
+        code: Option<SpannedExpr>,
137
+        quiet: bool,
138
+    },
139
+    Return {
140
+        value: Option<SpannedExpr>,
141
+    },
142
+    Goto {
143
+        label: u64,
144
+    },
145
+    ComputedGoto {
146
+        labels: Vec<u64>,
147
+        selector: SpannedExpr,
148
+    },
149
+    ArithmeticIf {
150
+        expr: SpannedExpr,
151
+        neg: u64,
152
+        zero: u64,
153
+        pos: u64,
154
+    },
113155
     /// Statement label on any executable statement: `10 i = i + 1`.
114156
     /// The parser emits this when it sees an integer literal at statement start.
115
-    Labeled { label: u64, stmt: Box<SpannedStmt> },
157
+    Labeled {
158
+        label: u64,
159
+        stmt: Box<SpannedStmt>,
160
+    },
116161
 
117162
     // ---- I/O ----
118
-    Write { controls: Vec<IoControl>, items: Vec<SpannedExpr> },
119
-    Read { controls: Vec<IoControl>, items: Vec<SpannedExpr> },
120
-    Open { specs: Vec<IoControl> },
121
-    Close { specs: Vec<IoControl> },
122
-    Inquire { specs: Vec<IoControl>, items: Vec<SpannedExpr> },
123
-    Rewind { specs: Vec<IoControl> },
124
-    Backspace { specs: Vec<IoControl> },
125
-    Endfile { specs: Vec<IoControl> },
126
-    Flush { specs: Vec<IoControl> },
127
-    Wait { specs: Vec<IoControl> },
163
+    Write {
164
+        controls: Vec<IoControl>,
165
+        items: Vec<SpannedExpr>,
166
+    },
167
+    Read {
168
+        controls: Vec<IoControl>,
169
+        items: Vec<SpannedExpr>,
170
+    },
171
+    Open {
172
+        specs: Vec<IoControl>,
173
+    },
174
+    Close {
175
+        specs: Vec<IoControl>,
176
+    },
177
+    Inquire {
178
+        specs: Vec<IoControl>,
179
+        items: Vec<SpannedExpr>,
180
+    },
181
+    Rewind {
182
+        specs: Vec<IoControl>,
183
+    },
184
+    Backspace {
185
+        specs: Vec<IoControl>,
186
+    },
187
+    Endfile {
188
+        specs: Vec<IoControl>,
189
+    },
190
+    Flush {
191
+        specs: Vec<IoControl>,
192
+    },
193
+    Wait {
194
+        specs: Vec<IoControl>,
195
+    },
128196
 
129197
     // ---- Memory ----
130
-    Allocate { items: Vec<SpannedExpr>, opts: Vec<IoControl> },
131
-    Deallocate { items: Vec<SpannedExpr>, opts: Vec<IoControl> },
132
-    Nullify { items: Vec<SpannedExpr> },
198
+    Allocate {
199
+        items: Vec<SpannedExpr>,
200
+        opts: Vec<IoControl>,
201
+    },
202
+    Deallocate {
203
+        items: Vec<SpannedExpr>,
204
+        opts: Vec<IoControl>,
205
+    },
206
+    Nullify {
207
+        items: Vec<SpannedExpr>,
208
+    },
133209
 
134210
     // ---- Other executable ----
135
-    Continue { label: Option<u64> },
136
-    Call { callee: SpannedExpr, args: Vec<crate::ast::expr::Argument> },
137
-    Print { format: SpannedExpr, items: Vec<SpannedExpr> },
138
-    Namelist { groups: Vec<(String, Vec<String>)> },
211
+    Continue {
212
+        label: Option<u64>,
213
+    },
214
+    Call {
215
+        callee: SpannedExpr,
216
+        args: Vec<crate::ast::expr::Argument>,
217
+    },
218
+    Print {
219
+        format: SpannedExpr,
220
+        items: Vec<SpannedExpr>,
221
+    },
222
+    Namelist {
223
+        groups: Vec<(String, Vec<String>)>,
224
+    },
139225
 
140226
     // ---- Declaration (embedded in statement context) ----
141227
     Declaration(SpannedDecl),
@@ -156,9 +242,15 @@ pub struct IoControl {
156242
 #[derive(Debug, Clone, PartialEq)]
157243
 pub enum TypeGuard {
158244
     /// TYPE IS (type_name) — exact type match.
159
-    TypeIs { type_name: String, body: Vec<SpannedStmt> },
245
+    TypeIs {
246
+        type_name: String,
247
+        body: Vec<SpannedStmt>,
248
+    },
160249
     /// CLASS IS (type_name) — matches type or any extension.
161
-    ClassIs { type_name: String, body: Vec<SpannedStmt> },
250
+    ClassIs {
251
+        type_name: String,
252
+        body: Vec<SpannedStmt>,
253
+    },
162254
     /// CLASS DEFAULT — fallback.
163255
     ClassDefault { body: Vec<SpannedStmt> },
164256
 }
@@ -174,7 +266,10 @@ pub struct CaseBlock {
174266
 #[derive(Debug, Clone, PartialEq)]
175267
 pub enum CaseSelector {
176268
     Value(SpannedExpr),
177
-    Range { low: Option<SpannedExpr>, high: Option<SpannedExpr> },
269
+    Range {
270
+        low: Option<SpannedExpr>,
271
+        high: Option<SpannedExpr>,
272
+    },
178273
     Default,
179274
 }
180275
 
src/ast/unit.rsmodified
22 lines changed — click to load
@@ -3,9 +3,9 @@
33
 //! Top-level compilation units: programs, modules, submodules,
44
 //! subroutines, functions, block data, and interface blocks.
55
 
6
-use super::Spanned;
76
 use super::decl::{SpannedDecl, TypeSpec};
87
 use super::stmt::SpannedStmt;
8
+use super::Spanned;
99
 
1010
 /// A spanned program unit.
1111
 pub type SpannedUnit = Spanned<ProgramUnit>;
@@ -119,8 +119,8 @@ pub enum InterfaceBody {
119119
 /// IMPORT statement.
120120
 #[derive(Debug, Clone, PartialEq)]
121121
 pub enum ImportStmt {
122
-    Default(Vec<String>),    // import :: name1, name2
123
-    All,                      // import, all
124
-    None,                     // import, none
125
-    Only(Vec<String>),        // import, only: name1, name2
122
+    Default(Vec<String>), // import :: name1, name2
123
+    All,                  // import, all
124
+    None,                 // import, none
125
+    Only(Vec<String>),    // import, only: name1, name2
126126
 }
src/codegen/linearscan.rsmodified
334 lines changed — click to load
@@ -8,9 +8,9 @@
88
 //! Callee-saved registers (x19-x28, d8-d15) are tracked — if used, the function
99
 //! prologue/epilogue must save/restore them.
1010
 
11
-use std::collections::{HashMap, HashSet};
12
-use super::mir::*;
1311
 use super::liveness::compute_liveness;
12
+use super::mir::*;
13
+use std::collections::{HashMap, HashSet};
1414
 
1515
 /// GP registers available for allocation (excludes x18, x29, x30, x31/sp).
1616
 /// Ordered: caller-saved first (prefer these to avoid save/restore overhead),
@@ -32,8 +32,8 @@ use super::liveness::compute_liveness;
3232
 /// of pressure and guarantees reloads never clash.
3333
 const GP_ALLOC_ORDER: [u8; 22] = [
3434
     // Caller-saved (temporary, no save needed)
35
-    12, 13, 14, 15,              // x12-x15
36
-    0, 1, 2, 3, 4, 5, 6, 7,      // x0-x7 (args, but available between calls)
35
+    12, 13, 14, 15, // x12-x15
36
+    0, 1, 2, 3, 4, 5, 6, 7, // x0-x7 (args, but available between calls)
3737
     // Callee-saved (must save/restore if used)
3838
     19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
3939
 ];
@@ -42,8 +42,7 @@ const GP_ALLOC_ORDER: [u8; 22] = [
4242
 /// d29, d30, d31 are reserved exclusively as spill reload scratch.
4343
 const FP_ALLOC_ORDER: [u8; 29] = [
4444
     // Caller-saved
45
-    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
46
-    0, 1, 2, 3, 4, 5, 6, 7,
45
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 1, 2, 3, 4, 5, 6, 7,
4746
     // Callee-saved
4847
     8, 9, 10, 11, 12, 13, 14, 15,
4948
 ];
@@ -104,7 +103,11 @@ pub fn linear_scan(mf: &mut MachineFunction) -> AllocResult {
104103
 
105104
         let reg_opt = if interval.crosses_call {
106105
             // Must use callee-saved. Find one in the free list.
107
-            let callee_range = if is_fp { &FP_CALLEE_SAVED } else { &GP_CALLEE_SAVED };
106
+            let callee_range = if is_fp {
107
+                &FP_CALLEE_SAVED
108
+            } else {
109
+                &GP_CALLEE_SAVED
110
+            };
108111
             let idx = free.iter().position(|r| callee_range.contains(r));
109112
             idx.map(|i| free.remove(i))
110113
         } else if let Some(hint) = interval.hint {
@@ -195,20 +198,29 @@ pub fn linear_scan(mf: &mut MachineFunction) -> AllocResult {
195198
         _ => 200,
196199
     });
197200
 
198
-    AllocResult { assignments, spills, callee_saved_used: callee_saved }
201
+    AllocResult {
202
+        assignments,
203
+        spills,
204
+        callee_saved_used: callee_saved,
205
+    }
199206
 }
200207
 
201208
 /// Apply allocation result: rewrite VReg operands to PhysReg, insert spill code.
202209
 /// For spilled operands, borrows a temporarily-free register from the allocation
203210
 /// pool rather than using dedicated scratch registers. This avoids wasting
204211
 /// registers in the pool and follows standard linear scan practice.
205
-pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness: &super::liveness::LivenessResult) {
206
-    let vreg_classes: HashMap<VRegId, RegClass> = mf.vregs.iter()
207
-        .map(|v| (v.id, v.class))
208
-        .collect();
212
+pub fn apply_allocation(
213
+    mf: &mut MachineFunction,
214
+    result: &AllocResult,
215
+    liveness: &super::liveness::LivenessResult,
216
+) {
217
+    let vreg_classes: HashMap<VRegId, RegClass> =
218
+        mf.vregs.iter().map(|v| (v.id, v.class)).collect();
209219
 
210220
     // Build interval lookup: for each vreg, its live range.
211
-    let intervals: HashMap<VRegId, (u32, u32)> = liveness.intervals.iter()
221
+    let intervals: HashMap<VRegId, (u32, u32)> = liveness
222
+        .intervals
223
+        .iter()
212224
         .map(|i| (i.vreg, (i.start, i.end)))
213225
         .collect();
214226
 
@@ -241,8 +253,8 @@ pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness
241253
             // index, so their order is load-bearing.
242254
             let mut gp_temps: Vec<u8> = Vec::new();
243255
             let mut fp_temps: Vec<u8> = Vec::new();
244
-            let mut sorted_assignments: Vec<(VRegId, PhysReg)> = result.assignments
245
-                .iter().map(|(&v, &p)| (v, p)).collect();
256
+            let mut sorted_assignments: Vec<(VRegId, PhysReg)> =
257
+                result.assignments.iter().map(|(&v, &p)| (v, p)).collect();
246258
             sorted_assignments.sort_by_key(|(v, _)| v.0);
247259
             for (vreg, phys) in &sorted_assignments {
248260
                 if let Some(&(start, end)) = intervals.get(vreg) {
@@ -257,8 +269,16 @@ pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness
257269
                 }
258270
             }
259271
             // Also include the dedicated fallback scratches in case no free regs found.
260
-            for &s in &GP_SPILL_SCRATCH { if !gp_temps.contains(&s) { gp_temps.push(s); } }
261
-            for &s in &FP_SPILL_SCRATCH { if !fp_temps.contains(&s) { fp_temps.push(s); } }
272
+            for &s in &GP_SPILL_SCRATCH {
273
+                if !gp_temps.contains(&s) {
274
+                    gp_temps.push(s);
275
+                }
276
+            }
277
+            for &s in &FP_SPILL_SCRATCH {
278
+                if !fp_temps.contains(&s) {
279
+                    fp_temps.push(s);
280
+                }
281
+            }
262282
 
263283
             // For spilled vregs used as inputs: borrow a temp register.
264284
             let mut loads = Vec::new();
@@ -268,24 +288,45 @@ pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness
268288
                 if let MachineOperand::VReg(vid) = op {
269289
                     if let Some(&offset) = result.spills.get(vid) {
270290
                         let class = vreg_classes.get(vid).copied().unwrap_or(RegClass::Gp64);
271
-                        let (temp_reg, load_op) = if matches!(class, RegClass::Fp32 | RegClass::Fp64) {
272
-                            let r = fp_temps.get(fp_temp_idx).copied().unwrap_or(FP_SPILL_SCRATCH[0]);
273
-                            fp_temp_idx += 1;
274
-                            let phys = if matches!(class, RegClass::Fp32) { PhysReg::Fp32(r) } else { PhysReg::Fp(r) };
275
-                            (phys, ArmOpcode::LdrFpImm)
276
-                        } else {
277
-                            let r = gp_temps.get(gp_temp_idx).copied().unwrap_or(GP_SPILL_SCRATCH[0]);
278
-                            gp_temp_idx += 1;
279
-                            let phys = if matches!(class, RegClass::Gp32) { PhysReg::Gp32(r) } else { PhysReg::Gp(r) };
280
-                            (phys, ArmOpcode::LdrImm)
281
-                        };
291
+                        let (temp_reg, load_op) =
292
+                            if matches!(class, RegClass::Fp32 | RegClass::Fp64) {
293
+                                let r = fp_temps
294
+                                    .get(fp_temp_idx)
295
+                                    .copied()
296
+                                    .unwrap_or(FP_SPILL_SCRATCH[0]);
297
+                                fp_temp_idx += 1;
298
+                                let phys = if matches!(class, RegClass::Fp32) {
299
+                                    PhysReg::Fp32(r)
300
+                                } else {
301
+                                    PhysReg::Fp(r)
302
+                                };
303
+                                (phys, ArmOpcode::LdrFpImm)
304
+                            } else {
305
+                                let r = gp_temps
306
+                                    .get(gp_temp_idx)
307
+                                    .copied()
308
+                                    .unwrap_or(GP_SPILL_SCRATCH[0]);
309
+                                gp_temp_idx += 1;
310
+                                let phys = if matches!(class, RegClass::Gp32) {
311
+                                    PhysReg::Gp32(r)
312
+                                } else {
313
+                                    PhysReg::Gp(r)
314
+                                };
315
+                                (phys, ArmOpcode::LdrImm)
316
+                            };
282317
                         loads.push((i, temp_reg, load_op, offset));
283318
                     }
284319
                 }
285320
             }
286321
 
287322
             for (op_idx, scratch, load_op, offset) in &loads {
288
-                if *op_idx == 0 && inst.def.as_ref().map(|d| result.spills.contains_key(d)).unwrap_or(false) {
323
+                if *op_idx == 0
324
+                    && inst
325
+                        .def
326
+                        .as_ref()
327
+                        .map(|d| result.spills.contains_key(d))
328
+                        .unwrap_or(false)
329
+                {
289330
                     continue;
290331
                 }
291332
                 new_insts.push(MachineInst {
@@ -315,11 +356,25 @@ pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness
315356
                 if let Some(&offset) = result.spills.get(def_vid) {
316357
                     let class = vreg_classes.get(def_vid).copied().unwrap_or(RegClass::Gp64);
317358
                     let temp_reg = if matches!(class, RegClass::Fp32 | RegClass::Fp64) {
318
-                        let r = fp_temps.get(def_temp_idx).copied().unwrap_or(FP_SPILL_SCRATCH[0]);
319
-                        if matches!(class, RegClass::Fp32) { PhysReg::Fp32(r) } else { PhysReg::Fp(r) }
359
+                        let r = fp_temps
360
+                            .get(def_temp_idx)
361
+                            .copied()
362
+                            .unwrap_or(FP_SPILL_SCRATCH[0]);
363
+                        if matches!(class, RegClass::Fp32) {
364
+                            PhysReg::Fp32(r)
365
+                        } else {
366
+                            PhysReg::Fp(r)
367
+                        }
320368
                     } else {
321
-                        let r = gp_temps.get(def_temp_idx).copied().unwrap_or(GP_SPILL_SCRATCH[0]);
322
-                        if matches!(class, RegClass::Gp32) { PhysReg::Gp32(r) } else { PhysReg::Gp(r) }
369
+                        let r = gp_temps
370
+                            .get(def_temp_idx)
371
+                            .copied()
372
+                            .unwrap_or(GP_SPILL_SCRATCH[0]);
373
+                        if matches!(class, RegClass::Gp32) {
374
+                            PhysReg::Gp32(r)
375
+                        } else {
376
+                            PhysReg::Gp(r)
377
+                        }
323378
                     };
324379
                     let scratch = temp_reg;
325380
                     // Replace def operand with scratch.
@@ -329,8 +384,12 @@ pub fn apply_allocation(mf: &mut MachineFunction, result: &AllocResult, liveness
329384
                         }
330385
                     }
331386
                     Some((scratch, offset, class))
332
-                } else { None }
333
-            } else { None };
387
+                } else {
388
+                    None
389
+                }
390
+            } else {
391
+                None
392
+            };
334393
 
335394
             rewritten.def = None;
336395
             new_insts.push(rewritten);
@@ -373,10 +432,14 @@ pub fn insert_callee_saves(mf: &mut MachineFunction, callee_saved: &[PhysReg]) {
373432
 
374433
     // Insert saves at the start of the entry block (after prologue setup).
375434
     // Find the insertion point: after the STP + ADD (prologue) instructions.
376
-    let prologue_end = mf.blocks[0].insts.iter().position(|i| {
377
-        // The prologue is StpPre followed by AddImm. Insert after those.
378
-        !matches!(i.opcode, ArmOpcode::StpPre | ArmOpcode::AddImm)
379
-    }).unwrap_or(0);
435
+    let prologue_end = mf.blocks[0]
436
+        .insts
437
+        .iter()
438
+        .position(|i| {
439
+            // The prologue is StpPre followed by AddImm. Insert after those.
440
+            !matches!(i.opcode, ArmOpcode::StpPre | ArmOpcode::AddImm)
441
+        })
442
+        .unwrap_or(0);
380443
 
381444
     // Emit saves, pairing consecutive same-class registers into STP.
382445
     // save_slots are ordered by increasing register number; slots are
@@ -421,10 +484,7 @@ pub fn insert_callee_saves(mf: &mut MachineFunction, callee_saved: &[PhysReg]) {
421484
 /// STP Xt1, Xt2, [Xn, #off] → Xt1 at off, Xt2 at off+8.
422485
 /// We pair as: STP slots[i+1].reg, slots[i].reg, [FP, #slots[i+1].offset]
423486
 /// because slots[i+1] has the lower (more negative) offset.
424
-fn emit_callee_store_pairs(
425
-    save_slots: &[(PhysReg, i32)],
426
-    restore: bool,
427
-) -> Vec<MachineInst> {
487
+fn emit_callee_store_pairs(save_slots: &[(PhysReg, i32)], restore: bool) -> Vec<MachineInst> {
428488
     let mut result = Vec::new();
429489
     let mut i = 0;
430490
     while i < save_slots.len() {
@@ -440,7 +500,11 @@ fn emit_callee_store_pairs(
440500
             // STP offset must fit in 7-bit signed × 8: range -512..504.
441501
             let in_range = (-512..=504).contains(&off2);
442502
             if same_class && adjacent && in_range {
443
-                let opcode = if restore { ArmOpcode::LdpOffset } else { ArmOpcode::StpOffset };
503
+                let opcode = if restore {
504
+                    ArmOpcode::LdpOffset
505
+                } else {
506
+                    ArmOpcode::StpOffset
507
+                };
444508
                 let (low_reg, high_reg) = (reg2, reg1);
445509
                 result.push(MachineInst {
446510
                     opcode,
@@ -459,10 +523,18 @@ fn emit_callee_store_pairs(
459523
         // Emit individual STR/LDR.
460524
         let (op, is_fp) = match reg1 {
461525
             PhysReg::Fp(_) | PhysReg::Fp32(_) => {
462
-                if restore { (ArmOpcode::LdrFpImm, true) } else { (ArmOpcode::StrFpImm, true) }
526
+                if restore {
527
+                    (ArmOpcode::LdrFpImm, true)
528
+                } else {
529
+                    (ArmOpcode::StrFpImm, true)
530
+                }
463531
             }
464532
             _ => {
465
-                if restore { (ArmOpcode::LdrImm, false) } else { (ArmOpcode::StrImm, false) }
533
+                if restore {
534
+                    (ArmOpcode::LdrImm, false)
535
+                } else {
536
+                    (ArmOpcode::StrImm, false)
537
+                }
466538
             }
467539
         };
468540
         let _ = is_fp;
@@ -473,7 +545,15 @@ fn emit_callee_store_pairs(
473545
                 MachineOperand::PhysReg(PhysReg::FP),
474546
                 MachineOperand::Imm(off1 as i64),
475547
             ],
476
-            def: if restore { Some(match reg1 { PhysReg::Gp(n) | PhysReg::Gp32(n) => crate::codegen::mir::VRegId(n.into()), PhysReg::Fp(n) | PhysReg::Fp32(n) => crate::codegen::mir::VRegId(n.into()), _ => crate::codegen::mir::VRegId(0) }) } else { None },
548
+            def: if restore {
549
+                Some(match reg1 {
550
+                    PhysReg::Gp(n) | PhysReg::Gp32(n) => crate::codegen::mir::VRegId(n.into()),
551
+                    PhysReg::Fp(n) | PhysReg::Fp32(n) => crate::codegen::mir::VRegId(n.into()),
552
+                    _ => crate::codegen::mir::VRegId(0),
553
+                })
554
+            } else {
555
+                None
556
+            },
477557
         });
478558
         i += 1;
479559
     }
@@ -517,7 +597,10 @@ const FP_SPILL_SCRATCH: [u8; 3] = [29, 30, 31];
517597
 fn spill_scratch(class: RegClass, idx: usize) -> (PhysReg, ArmOpcode) {
518598
     match class {
519599
         RegClass::Fp64 => (PhysReg::Fp(FP_SPILL_SCRATCH[idx % 3]), ArmOpcode::LdrFpImm),
520
-        RegClass::Fp32 => (PhysReg::Fp32(FP_SPILL_SCRATCH[idx % 3]), ArmOpcode::LdrFpImm),
600
+        RegClass::Fp32 => (
601
+            PhysReg::Fp32(FP_SPILL_SCRATCH[idx % 3]),
602
+            ArmOpcode::LdrFpImm,
603
+        ),
521604
         RegClass::Gp32 => (PhysReg::Gp32(GP_SPILL_SCRATCH[idx % 3]), ArmOpcode::LdrImm),
522605
         RegClass::Gp64 => (PhysReg::Gp(GP_SPILL_SCRATCH[idx % 3]), ArmOpcode::LdrImm),
523606
     }
@@ -526,10 +609,10 @@ fn spill_scratch(class: RegClass, idx: usize) -> (PhysReg, ArmOpcode) {
526609
 #[cfg(test)]
527610
 mod tests {
528611
     use super::*;
529
-    use crate::ir::types::*;
530
-    use crate::ir::inst::*;
531
-    use crate::ir::builder::FuncBuilder;
532612
     use crate::codegen::isel::select_function;
613
+    use crate::ir::builder::FuncBuilder;
614
+    use crate::ir::inst::*;
615
+    use crate::ir::types::*;
533616
 
534617
     #[test]
535618
     fn linear_scan_assigns_registers() {
@@ -544,9 +627,15 @@ mod tests {
544627
         let mut mf = select_function(&func);
545628
         let result = linear_scan(&mut mf);
546629
         // Should have assignments for the vregs.
547
-        assert!(!result.assignments.is_empty(), "should have register assignments");
630
+        assert!(
631
+            !result.assignments.is_empty(),
632
+            "should have register assignments"
633
+        );
548634
         // No spills needed for 3 vregs.
549
-        assert!(result.spills.is_empty(), "should not spill with only 3 vregs");
635
+        assert!(
636
+            result.spills.is_empty(),
637
+            "should not spill with only 3 vregs"
638
+        );
550639
     }
551640
 
552641
     #[test]
@@ -595,6 +684,10 @@ mod tests {
595684
         });
596685
         assert_eq!(mf.blocks[0].insts.len(), 2);
597686
         coalesce_moves(&mut mf);
598
-        assert_eq!(mf.blocks[0].insts.len(), 1, "self-move should be eliminated");
687
+        assert_eq!(
688
+            mf.blocks[0].insts.len(),
689
+            1,
690
+            "self-move should be eliminated"
691
+        );
599692
     }
600693
 }
src/codegen/liveness.rsmodified
140 lines changed — click to load
@@ -3,16 +3,16 @@
33
 //! Computes live intervals for each virtual register using backward
44
 //! dataflow. Used by the linear scan register allocator.
55
 
6
-use std::collections::{HashMap, BTreeSet};
76
 use super::mir::*;
7
+use std::collections::{BTreeSet, HashMap};
88
 
99
 /// A live interval: the range of instruction positions where a vreg is live.
1010
 #[derive(Debug, Clone)]
1111
 pub struct LiveInterval {
1212
     pub vreg: VRegId,
1313
     pub class: RegClass,
14
-    pub start: u32,   // first instruction position (definition)
15
-    pub end: u32,     // last instruction position (final use)
14
+    pub start: u32,         // first instruction position (definition)
15
+    pub end: u32,           // last instruction position (final use)
1616
     pub crosses_call: bool, // true if a BL instruction falls within [start, end]
1717
     /// Preferred physical register (hint). If set, the allocator tries this register first.
1818
     /// Used to avoid unnecessary moves (e.g., arg values prefer xN, return values prefer x0).
@@ -142,16 +142,26 @@ pub fn compute_liveness(mf: &MachineFunction) -> LivenessResult {
142142
         // Vregs live-in to this block: extend their interval to block start.
143143
         if let Some(lin) = live_in.get(&block.id) {
144144
             for &vreg in lin {
145
-                ends.entry(vreg).and_modify(|e| *e = (*e).max(b_end)).or_insert(b_end);
146
-                starts.entry(vreg).and_modify(|s| *s = (*s).min(b_start)).or_insert(b_start);
145
+                ends.entry(vreg)
146
+                    .and_modify(|e| *e = (*e).max(b_end))
147
+                    .or_insert(b_end);
148
+                starts
149
+                    .entry(vreg)
150
+                    .and_modify(|s| *s = (*s).min(b_start))
151
+                    .or_insert(b_start);
147152
             }
148153
         }
149154
 
150155
         // Vregs live-out of this block: extend their interval to block end.
151156
         if let Some(lout) = live_out.get(&block.id) {
152157
             for &vreg in lout {
153
-                ends.entry(vreg).and_modify(|e| *e = (*e).max(b_end)).or_insert(b_end);
154
-                starts.entry(vreg).and_modify(|s| *s = (*s).min(b_start)).or_insert(b_start);
158
+                ends.entry(vreg)
159
+                    .and_modify(|e| *e = (*e).max(b_end))
160
+                    .or_insert(b_end);
161
+                starts
162
+                    .entry(vreg)
163
+                    .and_modify(|s| *s = (*s).min(b_start))
164
+                    .or_insert(b_start);
155165
             }
156166
         }
157167
 
@@ -159,13 +169,23 @@ pub fn compute_liveness(mf: &MachineFunction) -> LivenessResult {
159169
         for (i, inst) in block.insts.iter().enumerate() {
160170
             let p = position_map[&(block.id, i)];
161171
             if let Some(def) = &inst.def {
162
-                starts.entry(*def).and_modify(|s| *s = (*s).min(p)).or_insert(p);
163
-                ends.entry(*def).and_modify(|e| *e = (*e).max(p)).or_insert(p);
172
+                starts
173
+                    .entry(*def)
174
+                    .and_modify(|s| *s = (*s).min(p))
175
+                    .or_insert(p);
176
+                ends.entry(*def)
177
+                    .and_modify(|e| *e = (*e).max(p))
178
+                    .or_insert(p);
164179
             }
165180
             for op in &inst.operands {
166181
                 if let MachineOperand::VReg(vid) = op {
167
-                    ends.entry(*vid).and_modify(|e| *e = (*e).max(p)).or_insert(p);
168
-                    starts.entry(*vid).and_modify(|s| *s = (*s).min(p)).or_insert(p);
182
+                    ends.entry(*vid)
183
+                        .and_modify(|e| *e = (*e).max(p))
184
+                        .or_insert(p);
185
+                    starts
186
+                        .entry(*vid)
187
+                        .and_modify(|s| *s = (*s).min(p))
188
+                        .or_insert(p);
169189
                 }
170190
             }
171191
         }
@@ -185,17 +205,24 @@ pub fn compute_liveness(mf: &MachineFunction) -> LivenessResult {
185205
     call_positions.sort();
186206
 
187207
     // Build intervals.
188
-    let vreg_classes: HashMap<VRegId, RegClass> = mf.vregs.iter()
189
-        .map(|v| (v.id, v.class))
190
-        .collect();
208
+    let vreg_classes: HashMap<VRegId, RegClass> =
209
+        mf.vregs.iter().map(|v| (v.id, v.class)).collect();
191210
 
192
-    let mut intervals: Vec<LiveInterval> = starts.iter()
211
+    let mut intervals: Vec<LiveInterval> = starts
212
+        .iter()
193213
         .filter_map(|(&vreg, &start)| {
194214
             let end = ends.get(&vreg).copied()?;
195215
             let class = vreg_classes.get(&vreg).copied().unwrap_or(RegClass::Gp64);
196216
             // Check if any call falls within [start, end].
197217
             let crosses_call = call_positions.iter().any(|&cp| cp > start && cp < end);
198
-            Some(LiveInterval { vreg, class, start, end, crosses_call, hint: None })
218
+            Some(LiveInterval {
219
+                vreg,
220
+                class,
221
+                start,
222
+                end,
223
+                crosses_call,
224
+                hint: None,
225
+            })
199226
         })
200227
         .collect();
201228
 
@@ -210,16 +237,19 @@ pub fn compute_liveness(mf: &MachineFunction) -> LivenessResult {
210237
     // exposed clearly when mem2reg started perturbing vreg counts.
211238
     intervals.sort_by_key(|i| (i.start, i.vreg.0));
212239
 
213
-    LivenessResult { intervals, num_positions }
240
+    LivenessResult {
241
+        intervals,
242
+        num_positions,
243
+    }
214244
 }
215245
 
216246
 #[cfg(test)]
217247
 mod tests {
218248
     use super::*;
219
-    use crate::ir::types::*;
220
-    use crate::ir::inst::*;
221
-    use crate::ir::builder::FuncBuilder;
222249
     use crate::codegen::isel::select_function;
250
+    use crate::ir::builder::FuncBuilder;
251
+    use crate::ir::inst::*;
252
+    use crate::ir::types::*;
223253
 
224254
     #[test]
225255
     fn liveness_simple_function() {
@@ -250,8 +280,10 @@ mod tests {
250280
         let mf = select_function(&func);
251281
         let result = compute_liveness(&mf);
252282
         // Should have some Fp64 intervals.
253
-        assert!(result.intervals.iter().any(|i| i.class == RegClass::Fp64),
254
-            "should have Fp64 intervals");
283
+        assert!(
284
+            result.intervals.iter().any(|i| i.class == RegClass::Fp64),
285
+            "should have Fp64 intervals"
286
+        );
255287
     }
256288
 
257289
     #[test]
src/codegen/mod.rsmodified
15 lines changed — click to load
@@ -3,11 +3,11 @@
33
 //! Instruction selection, register allocation, stack frame layout,
44
 //! and emission of machine instructions for the afs-as assembler.
55
 
6
-pub mod mir;
6
+pub mod emit;
77
 pub mod isel;
8
-pub mod liveness;
9
-pub mod regalloc;
108
 pub mod linearscan;
11
-pub mod emit;
9
+pub mod liveness;
10
+pub mod mir;
1211
 pub mod peephole;
12
+pub mod regalloc;
1313
 pub mod tailcall;
src/codegen/peephole.rsmodified
227 lines changed — click to load
@@ -23,7 +23,7 @@
2323
 //! After fusion the FMUL instruction is removed and the FADD/FSUB is
2424
 //! replaced by the three-source FMA instruction.
2525
 
26
-use super::mir::{MachineFunction, MachineInst, MachineOperand, ArmOpcode, VRegId};
26
+use super::mir::{ArmOpcode, MachineFunction, MachineInst, MachineOperand, VRegId};
2727
 use std::collections::HashMap;
2828
 
2929
 /// Run all peephole passes on a machine function.
@@ -67,7 +67,10 @@ fn fma_fuse_block(mf: &mut MachineFunction, mb_idx: usize) {
6767
 
6868
     // Map: vreg defined by a fmul instruction → (block-instruction-index, precision)
6969
     #[derive(Clone, Copy)]
70
-    enum Prec { S, D }
70
+    enum Prec {
71
+        S,
72
+        D,
73
+    }
7174
     let mut fmul_defs: HashMap<VRegId, (usize, Prec)> = HashMap::new();
7275
 
7376
     for (i, inst) in block.insts.iter().enumerate() {
@@ -108,18 +111,28 @@ fn fma_fuse_block(mf: &mut MachineFunction, mb_idx: usize) {
108111
             ArmOpcode::FsubD => (false, true, false),
109112
             _ => continue,
110113
         };
111
-        if inst.operands.len() < 3 { continue; }
114
+        if inst.operands.len() < 3 {
115
+            continue;
116
+        }
112117
 
113118
         // operands: [dest, src0, src1]
114
-        let src0 = match &inst.operands[1] { MachineOperand::VReg(v) => *v, _ => continue };
115
-        let src1 = match &inst.operands[2] { MachineOperand::VReg(v) => *v, _ => continue };
119
+        let src0 = match &inst.operands[1] {
120
+            MachineOperand::VReg(v) => *v,
121
+            _ => continue,
122
+        };
123
+        let src1 = match &inst.operands[2] {
124
+            MachineOperand::VReg(v) => *v,
125
+            _ => continue,
126
+        };
116127
 
117128
         // Check if src0 is a single-use fmul result.
118
-        let try_fuse_src0 = fmul_defs.get(&src0)
129
+        let try_fuse_src0 = fmul_defs
130
+            .get(&src0)
119131
             .filter(|_| use_count.get(&src0).copied().unwrap_or(0) == 1);
120132
         // Check if src1 is a single-use fmul result.
121133
         let try_fuse_src1 = if is_add {
122
-            fmul_defs.get(&src1)
134
+            fmul_defs
135
+                .get(&src1)
123136
                 .filter(|_| use_count.get(&src1).copied().unwrap_or(0) == 1)
124137
         } else {
125138
             None // fsub(c, fmul(a,b)): src0=c, src1=fmul → handled separately
@@ -129,50 +142,120 @@ fn fma_fuse_block(mf: &mut MachineFunction, mb_idx: usize) {
129142
             // fadd(fmul(a,b), c) → FMADD(a, b, c)
130143
             if let Some(&(mul_idx, _)) = try_fuse_src0 {
131144
                 let mul_inst = &block.insts[mul_idx];
132
-                let n = match &mul_inst.operands[1] { MachineOperand::VReg(v) => *v, _ => continue };
133
-                let m = match &mul_inst.operands[2] { MachineOperand::VReg(v) => *v, _ => continue };
134
-                let opcode = if prec_s { ArmOpcode::FmaddS } else { ArmOpcode::FmaddD };
135
-                plans.push(FusionPlan { add_idx: i, mul_idx, new_opcode: opcode, n, m, a: src1 });
145
+                let n = match &mul_inst.operands[1] {
146
+                    MachineOperand::VReg(v) => *v,
147
+                    _ => continue,
148
+                };
149
+                let m = match &mul_inst.operands[2] {
150
+                    MachineOperand::VReg(v) => *v,
151
+                    _ => continue,
152
+                };
153
+                let opcode = if prec_s {
154
+                    ArmOpcode::FmaddS
155
+                } else {
156
+                    ArmOpcode::FmaddD
157
+                };
158
+                plans.push(FusionPlan {
159
+                    add_idx: i,
160
+                    mul_idx,
161
+                    new_opcode: opcode,
162
+                    n,
163
+                    m,
164
+                    a: src1,
165
+                });
136166
             } else if let Some(&(mul_idx, _)) = try_fuse_src1 {
137167
                 // fadd(c, fmul(a,b)) → FMADD(a, b, c)  [commuted]
138168
                 let mul_inst = &block.insts[mul_idx];
139
-                let n = match &mul_inst.operands[1] { MachineOperand::VReg(v) => *v, _ => continue };
140
-                let m = match &mul_inst.operands[2] { MachineOperand::VReg(v) => *v, _ => continue };
141
-                let opcode = if prec_s { ArmOpcode::FmaddS } else { ArmOpcode::FmaddD };
142
-                plans.push(FusionPlan { add_idx: i, mul_idx, new_opcode: opcode, n, m, a: src0 });
169
+                let n = match &mul_inst.operands[1] {
170
+                    MachineOperand::VReg(v) => *v,
171
+                    _ => continue,
172
+                };
173
+                let m = match &mul_inst.operands[2] {
174
+                    MachineOperand::VReg(v) => *v,
175
+                    _ => continue,
176
+                };
177
+                let opcode = if prec_s {
178
+                    ArmOpcode::FmaddS
179
+                } else {
180
+                    ArmOpcode::FmaddD
181
+                };
182
+                plans.push(FusionPlan {
183
+                    add_idx: i,
184
+                    mul_idx,
185
+                    new_opcode: opcode,
186
+                    n,
187
+                    m,
188
+                    a: src0,
189
+                });
143190
             }
144191
         } else if is_sub {
145192
             // fsub(fmul(a,b), c) → FNMSUB(a, b, c)  [result = a*b - c]
146193
             if let Some(&(mul_idx, _)) = try_fuse_src0 {
147194
                 let mul_inst = &block.insts[mul_idx];
148
-                let n = match &mul_inst.operands[1] { MachineOperand::VReg(v) => *v, _ => continue };
149
-                let m = match &mul_inst.operands[2] { MachineOperand::VReg(v) => *v, _ => continue };
150
-                let opcode = if prec_s { ArmOpcode::FnmsubS } else { ArmOpcode::FnmsubD };
151
-                plans.push(FusionPlan { add_idx: i, mul_idx, new_opcode: opcode, n, m, a: src1 });
195
+                let n = match &mul_inst.operands[1] {
196
+                    MachineOperand::VReg(v) => *v,
197
+                    _ => continue,
198
+                };
199
+                let m = match &mul_inst.operands[2] {
200
+                    MachineOperand::VReg(v) => *v,
201
+                    _ => continue,
202
+                };
203
+                let opcode = if prec_s {
204
+                    ArmOpcode::FnmsubS
205
+                } else {
206
+                    ArmOpcode::FnmsubD
207
+                };
208
+                plans.push(FusionPlan {
209
+                    add_idx: i,
210
+                    mul_idx,
211
+                    new_opcode: opcode,
212
+                    n,
213
+                    m,
214
+                    a: src1,
215
+                });
152216
             }
153217
             // fsub(c, fmul(a,b)) → FMSUB(a, b, c)  [result = c - a*b]
154218
             // src0=c, src1=fmul_result
155
-            let try_fuse_sub1 = fmul_defs.get(&src1)
219
+            let try_fuse_sub1 = fmul_defs
220
+                .get(&src1)
156221
                 .filter(|_| use_count.get(&src1).copied().unwrap_or(0) == 1);
157222
             if let Some(&(mul_idx, _)) = try_fuse_sub1 {
158223
                 let mul_inst = &block.insts[mul_idx];
159
-                let n = match &mul_inst.operands[1] { MachineOperand::VReg(v) => *v, _ => continue };
160
-                let m = match &mul_inst.operands[2] { MachineOperand::VReg(v) => *v, _ => continue };
161
-                let opcode = if prec_s { ArmOpcode::FmsubS } else { ArmOpcode::FmsubD };
162
-                plans.push(FusionPlan { add_idx: i, mul_idx, new_opcode: opcode, n, m, a: src0 });
224
+                let n = match &mul_inst.operands[1] {
225
+                    MachineOperand::VReg(v) => *v,
226
+                    _ => continue,
227
+                };
228
+                let m = match &mul_inst.operands[2] {
229
+                    MachineOperand::VReg(v) => *v,
230
+                    _ => continue,
231
+                };
232
+                let opcode = if prec_s {
233
+                    ArmOpcode::FmsubS
234
+                } else {
235
+                    ArmOpcode::FmsubD
236
+                };
237
+                plans.push(FusionPlan {
238
+                    add_idx: i,
239
+                    mul_idx,
240
+                    new_opcode: opcode,
241
+                    n,
242
+                    m,
243
+                    a: src0,
244
+                });
163245
             }
164246
         }
165247
     }
166248
 
167
-    if plans.is_empty() { return; }
249
+    if plans.is_empty() {
250
+        return;
251
+    }
168252
 
169253
     // Apply plans in reverse order of add_idx to keep indices stable.
170254
     plans.sort_by(|a, b| b.add_idx.cmp(&a.add_idx));
171255
 
172256
     // Collect mul_idxs to remove.
173
-    let mut remove_idxs: std::collections::HashSet<usize> = plans.iter()
174
-        .map(|p| p.mul_idx)
175
-        .collect();
257
+    let mut remove_idxs: std::collections::HashSet<usize> =
258
+        plans.iter().map(|p| p.mul_idx).collect();
176259
 
177260
     // Rewrite the block.
178261
     let block = &mut mf.blocks[mb_idx];
@@ -201,8 +284,9 @@ fn fma_fuse_block(mf: &mut MachineFunction, mb_idx: usize) {
201284
 #[cfg(test)]
202285
 mod tests {
203286
     use super::*;
204
-    use crate::codegen::mir::{MachineFunction, MachineBlock, MachineInst,
205
-        MachineOperand, ArmOpcode, MBlockId, RegClass};
287
+    use crate::codegen::mir::{
288
+        ArmOpcode, MBlockId, MachineBlock, MachineFunction, MachineInst, MachineOperand, RegClass,
289
+    };
206290
 
207291
     fn mf_with_insts(insts: Vec<MachineInst>) -> MachineFunction {
208292
         let mut mf = MachineFunction::new("test".into());
@@ -211,12 +295,20 @@ mod tests {
211295
             mf.new_vreg(RegClass::Fp32);
212296
         }
213297
         let bid = MBlockId(0);
214
-        mf.blocks = vec![MachineBlock { id: bid, label: "entry".into(), insts }];
298
+        mf.blocks = vec![MachineBlock {
299
+            id: bid,
300
+            label: "entry".into(),
301
+            insts,
302
+        }];
215303
         mf
216304
     }
217305
 
218
-    fn vreg(v: u32) -> MachineOperand { MachineOperand::VReg(VRegId(v)) }
219
-    fn vid(v: u32) -> VRegId { VRegId(v) }
306
+    fn vreg(v: u32) -> MachineOperand {
307
+        MachineOperand::VReg(VRegId(v))
308
+    }
309
+    fn vid(v: u32) -> VRegId {
310
+        VRegId(v)
311
+    }
220312
 
221313
     /// fadd(fmul(v1, v2), v3) → fmadd(v1, v2, v3)
222314
     #[test]
src/codegen/regalloc.rsmodified
113 lines changed — click to load
@@ -10,8 +10,8 @@
1010
 //!
1111
 //! This will be replaced by linear scan allocation in Sprint 21.
1212
 
13
-use std::collections::HashMap;
1413
 use super::mir::*;
14
+use std::collections::HashMap;
1515
 
1616
 /// Integer scratch registers (caller-saved, safe to clobber).
1717
 const GP_SCRATCH: [u8; 3] = [9, 10, 11];
@@ -36,9 +36,8 @@ pub fn regalloc_naive(mf: &mut MachineFunction) {
3636
     }
3737
 
3838
     // Build class map for quick lookup.
39
-    let vreg_classes: HashMap<VRegId, RegClass> = mf.vregs.iter()
40
-        .map(|v| (v.id, v.class))
41
-        .collect();
39
+    let vreg_classes: HashMap<VRegId, RegClass> =
40
+        mf.vregs.iter().map(|v| (v.id, v.class)).collect();
4241
 
4342
     // Phase 2: rewrite each block's instructions.
4443
     for block_idx in 0..mf.blocks.len() {
@@ -114,7 +113,10 @@ pub fn regalloc_naive(mf: &mut MachineFunction) {
114113
             // Replace the def operand (first operand if it matches def).
115114
             let def_scratch = if let Some(def_vid) = def_vreg {
116115
                 if let Some(&offset) = vreg_slots.get(&def_vid) {
117
-                    let class = vreg_classes.get(&def_vid).copied().unwrap_or(RegClass::Gp64);
116
+                    let class = vreg_classes
117
+                        .get(&def_vid)
118
+                        .copied()
119
+                        .unwrap_or(RegClass::Gp64);
118120
                     let scratch = match class {
119121
                         RegClass::Fp64 => PhysReg::Fp(FP_SCRATCH[0]),
120122
                         RegClass::Fp32 => PhysReg::Fp32(FP_SCRATCH[0]),
@@ -130,8 +132,12 @@ pub fn regalloc_naive(mf: &mut MachineFunction) {
130132
                     }
131133
 
132134
                     Some((scratch, offset, class))
133
-                } else { None }
134
-            } else { None };
135
+                } else {
136
+                    None
137
+                }
138
+            } else {
139
+                None
140
+            };
135141
 
136142
             // Emit the rewritten instruction.
137143
             rewritten.def = None; // physical regs don't track defs
@@ -162,10 +168,10 @@ pub fn regalloc_naive(mf: &mut MachineFunction) {
162168
 #[cfg(test)]
163169
 mod tests {
164170
     use super::*;
165
-    use crate::ir::types::*;
166
-    use crate::ir::inst::*;
167
-    use crate::ir::builder::FuncBuilder;
168171
     use crate::codegen::isel::select_function;
172
+    use crate::ir::builder::FuncBuilder;
173
+    use crate::ir::inst::*;
174
+    use crate::ir::types::*;
169175
 
170176
     #[test]
171177
     fn regalloc_replaces_vregs() {
@@ -184,8 +190,11 @@ mod tests {
184190
         for block in &mf.blocks {
185191
             for inst in &block.insts {
186192
                 for op in &inst.operands {
187
-                    assert!(!matches!(op, MachineOperand::VReg(_)),
188
-                        "vreg still present after regalloc: {:?}", inst);
193
+                    assert!(
194
+                        !matches!(op, MachineOperand::VReg(_)),
195
+                        "vreg still present after regalloc: {:?}",
196
+                        inst
197
+                    );
189198
                 }
190199
             }
191200
         }
@@ -204,7 +213,10 @@ mod tests {
204213
         let mut mf = select_function(&func);
205214
         let before = mf.frame.size;
206215
         regalloc_naive(&mut mf);
207
-        assert!(mf.frame.size >= before, "frame should grow to accommodate spill slots");
216
+        assert!(
217
+            mf.frame.size >= before,
218
+            "frame should grow to accommodate spill slots"
219
+        );
208220
     }
209221
 
210222
     #[test]
@@ -223,16 +235,22 @@ mod tests {
223235
         // Should use x9, x10, x11 as scratch registers.
224236
         let uses_scratch = mf.blocks.iter().any(|b| {
225237
             b.insts.iter().any(|i| {
226
-                i.operands.iter().any(|op| matches!(op,
227
-                    MachineOperand::PhysReg(PhysReg::Gp(9)) |
228
-                    MachineOperand::PhysReg(PhysReg::Gp(10)) |
229
-                    MachineOperand::PhysReg(PhysReg::Gp(11)) |
230
-                    MachineOperand::PhysReg(PhysReg::Gp32(9)) |
231
-                    MachineOperand::PhysReg(PhysReg::Gp32(10)) |
232
-                    MachineOperand::PhysReg(PhysReg::Gp32(11))
233
-                ))
238
+                i.operands.iter().any(|op| {
239
+                    matches!(
240
+                        op,
241
+                        MachineOperand::PhysReg(PhysReg::Gp(9))
242
+                            | MachineOperand::PhysReg(PhysReg::Gp(10))
243
+                            | MachineOperand::PhysReg(PhysReg::Gp(11))
244
+                            | MachineOperand::PhysReg(PhysReg::Gp32(9))
245
+                            | MachineOperand::PhysReg(PhysReg::Gp32(10))
246
+                            | MachineOperand::PhysReg(PhysReg::Gp32(11))
247
+                    )
248
+                })
234249
             })
235250
         });
236
-        assert!(uses_scratch, "should use scratch registers x9-x11 or w9-w11");
251
+        assert!(
252
+            uses_scratch,
253
+            "should use scratch registers x9-x11 or w9-w11"
254
+        );
237255
     }
238256
 }
src/codegen/tailcall.rsmodified
228 lines changed — click to load
@@ -37,8 +37,8 @@
3737
 //! * Gate: we don't fire on non-void calls where a non-trivial result-capture
3838
 //!   sequence remains (e.g., `MOV x1, x0`) — those are left alone.
3939
 
40
-use std::collections::HashSet;
4140
 use super::mir::{ArmOpcode, MachineFunction, MachineInst, MachineOperand, PhysReg};
41
+use std::collections::HashSet;
4242
 
4343
 /// Run tail call optimization on a single machine function.
4444
 ///
@@ -47,11 +47,17 @@ use super::mir::{ArmOpcode, MachineFunction, MachineInst, MachineOperand, PhysRe
4747
 pub fn tail_call_opt(mf: &mut MachineFunction) {
4848
     for block in &mut mf.blocks {
4949
         let n = block.insts.len();
50
-        if n < 2 { continue; }
50
+        if n < 2 {
51
+            continue;
52
+        }
5153
 
5254
         // Epilogue is always `LdpPost; Ret` at the very end.
53
-        if block.insts[n - 1].opcode != ArmOpcode::Ret { continue; }
54
-        if block.insts[n - 2].opcode != ArmOpcode::LdpPost { continue; }
55
+        if block.insts[n - 1].opcode != ArmOpcode::Ret {
56
+            continue;
57
+        }
58
+        if block.insts[n - 2].opcode != ArmOpcode::LdpPost {
59
+            continue;
60
+        }
5561
 
5662
         let ldp_idx = n - 2;
5763
 
@@ -62,9 +68,7 @@ pub fn tail_call_opt(mf: &mut MachineFunction) {
6268
         while bl_candidate > 0 {
6369
             bl_candidate -= 1;
6470
             match block.insts[bl_candidate].opcode {
65
-                ArmOpcode::LdpOffset
66
-                | ArmOpcode::LdrImm
67
-                | ArmOpcode::LdrFpImm => {
71
+                ArmOpcode::LdpOffset | ArmOpcode::LdrImm | ArmOpcode::LdrFpImm => {
6872
                     // Callee-save restore — keep scanning backwards.
6973
                 }
7074
                 ArmOpcode::Bl => {
@@ -80,8 +84,12 @@ pub fn tail_call_opt(mf: &mut MachineFunction) {
8084
         }
8185
 
8286
         // Sentinel or scanned to index 0 without finding Bl.
83
-        if bl_candidate == usize::MAX { continue; }
84
-        if block.insts[bl_candidate].opcode != ArmOpcode::Bl { continue; }
87
+        if bl_candidate == usize::MAX {
88
+            continue;
89
+        }
90
+        if block.insts[bl_candidate].opcode != ArmOpcode::Bl {
91
+            continue;
92
+        }
8593
 
8694
         // SAFETY: reject TCO when any argument register (x0–x7) holds a value
8795
         // derived from our frame pointer (e.g. a pointer to a stack-allocated
@@ -97,7 +105,7 @@ pub fn tail_call_opt(mf: &mut MachineFunction) {
97105
         // Extract the call target from the Bl operand.
98106
         let label = match block.insts[bl_candidate].operands.first() {
99107
             Some(MachineOperand::Extern(s)) => s.clone(),
100
-            _ => continue,  // indirect call or unexpected operand — skip
108
+            _ => continue, // indirect call or unexpected operand — skip
101109
         };
102110
 
103111
         // Transform:
@@ -149,7 +157,9 @@ fn has_frame_derived_arg(insts: &[MachineInst]) -> bool {
149157
             // sub xN, x29, #imm  →  xN holds a frame-relative address.
150158
             ArmOpcode::SubImm => {
151159
                 if op_is_fp(inst, 1) {
152
-                    if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
160
+                    if let Some(n) = op_gp(inst, 0) {
161
+                        tainted_regs.insert(n);
162
+                    }
153163
                 }
154164
             }
155165
             // add xN, xM, xP  (GEP: propagate taint from either source)
@@ -157,21 +167,25 @@ fn has_frame_derived_arg(insts: &[MachineInst]) -> bool {
157167
                 if op_gp(inst, 1).is_some_and(|n| tainted_regs.contains(&n))
158168
                     || op_gp(inst, 2).is_some_and(|n| tainted_regs.contains(&n))
159169
                 {
160
-                    if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
170
+                    if let Some(n) = op_gp(inst, 0) {
171
+                        tainted_regs.insert(n);
172
+                    }
161173
                 }
162174
             }
163175
             // add xN, xM, #imm  (GEP with constant offset / address arithmetic)
164176
             ArmOpcode::AddImm => {
165
-                if op_is_fp(inst, 1)
166
-                    || op_gp(inst, 1).is_some_and(|n| tainted_regs.contains(&n))
167
-                {
168
-                    if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
177
+                if op_is_fp(inst, 1) || op_gp(inst, 1).is_some_and(|n| tainted_regs.contains(&n)) {
178
+                    if let Some(n) = op_gp(inst, 0) {
179
+                        tainted_regs.insert(n);
180
+                    }
169181
                 }
170182
             }
171183
             // mov xN, xM  (register copy — propagates taint to arg reg)
172184
             ArmOpcode::MovReg => {
173185
                 if op_gp(inst, 1).is_some_and(|n| tainted_regs.contains(&n)) {
174
-                    if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
186
+                    if let Some(n) = op_gp(inst, 0) {
187
+                        tainted_regs.insert(n);
188
+                    }
175189
                 }
176190
             }
177191
             // mul xN, xM, xP  (index computation in GEP; conservative)
@@ -179,15 +193,17 @@ fn has_frame_derived_arg(insts: &[MachineInst]) -> bool {
179193
                 if op_gp(inst, 1).is_some_and(|n| tainted_regs.contains(&n))
180194
                     || op_gp(inst, 2).is_some_and(|n| tainted_regs.contains(&n))
181195
                 {
182
-                    if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
196
+                    if let Some(n) = op_gp(inst, 0) {
197
+                        tainted_regs.insert(n);
198
+                    }
183199
                 }
184200
             }
185201
             // str xN, [x29, #off] — if xN is tainted, the slot becomes tainted.
186202
             ArmOpcode::StrImm => {
187
-                if op_gp(inst, 0).is_some_and(|n| tainted_regs.contains(&n))
188
-                    && op_is_fp(inst, 1)
189
-                {
190
-                    if let Some(off) = op_fp_offset(inst, 2) { tainted_slots.insert(off); }
203
+                if op_gp(inst, 0).is_some_and(|n| tainted_regs.contains(&n)) && op_is_fp(inst, 1) {
204
+                    if let Some(off) = op_fp_offset(inst, 2) {
205
+                        tainted_slots.insert(off);
206
+                    }
191207
                 }
192208
             }
193209
             // ldr xN, [x29, #off] — if the slot is tainted, xN becomes tainted.
@@ -195,7 +211,9 @@ fn has_frame_derived_arg(insts: &[MachineInst]) -> bool {
195211
                 if op_is_fp(inst, 1) {
196212
                     if let Some(off) = op_fp_offset(inst, 2) {
197213
                         if tainted_slots.contains(&off) {
198
-                            if let Some(n) = op_gp(inst, 0) { tainted_regs.insert(n); }
214
+                            if let Some(n) = op_gp(inst, 0) {
215
+                                tainted_regs.insert(n);
216
+                            }
199217
                         }
200218
                     }
201219
                 }
@@ -247,7 +265,11 @@ mod tests {
247265
     use crate::codegen::mir::*;
248266
 
249267
     fn make_block(insts: Vec<MachineInst>) -> MachineBlock {
250
-        MachineBlock { label: "test".into(), insts, id: MBlockId(0) }
268
+        MachineBlock {
269
+            label: "test".into(),
270
+            insts,
271
+            id: MBlockId(0),
272
+        }
251273
     }
252274
 
253275
     fn bl(label: &str) -> MachineInst {
@@ -271,7 +293,11 @@ mod tests {
271293
     }
272294
 
273295
     fn ret() -> MachineInst {
274
-        MachineInst { opcode: ArmOpcode::Ret, operands: vec![], def: None }
296
+        MachineInst {
297
+            opcode: ArmOpcode::Ret,
298
+            operands: vec![],
299
+            def: None,
300
+        }
275301
     }
276302
 
277303
     fn ldr_callee_restore() -> MachineInst {
@@ -300,27 +326,25 @@ mod tests {
300326
     #[test]
301327
     fn void_tail_call_no_callee_saves() {
302328
         // Pattern: Bl; LdpPost; Ret → LdpPost; B
303
-        let mut mf = build_mf(vec![
304
-            vec![bl("_foo"), ldp_post(), ret()],
305
-        ]);
329
+        let mut mf = build_mf(vec![vec![bl("_foo"), ldp_post(), ret()]]);
306330
         tail_call_opt(&mut mf);
307331
         let insts = &mf.blocks[0].insts;
308332
         // Should now be: LdpPost, B _foo
309333
         assert_eq!(insts.len(), 2);
310334
         assert_eq!(insts[0].opcode, ArmOpcode::LdpPost);
311335
         assert_eq!(insts[1].opcode, ArmOpcode::B);
312
-        assert_eq!(
313
-            insts[1].operands[0],
314
-            MachineOperand::Extern("_foo".into())
315
-        );
336
+        assert_eq!(insts[1].operands[0], MachineOperand::Extern("_foo".into()));
316337
     }
317338
 
318339
     #[test]
319340
     fn void_tail_call_with_callee_restore() {
320341
         // Pattern: Bl; LdrImm(restore); LdpPost; Ret → LdrImm; LdpPost; B
321
-        let mut mf = build_mf(vec![
322
-            vec![bl("_bar"), ldr_callee_restore(), ldp_post(), ret()],
323
-        ]);
342
+        let mut mf = build_mf(vec![vec![
343
+            bl("_bar"),
344
+            ldr_callee_restore(),
345
+            ldp_post(),
346
+            ret(),
347
+        ]]);
324348
         tail_call_opt(&mut mf);
325349
         let insts = &mf.blocks[0].insts;
326350
         assert_eq!(insts.len(), 3);
@@ -340,16 +364,18 @@ mod tests {
340364
             ],
341365
             def: None,
342366
         };
343
-        let mut mf = build_mf(vec![
344
-            vec![bl("_baz"), mov_result, ldp_post(), ret()],
345
-        ]);
367
+        let mut mf = build_mf(vec![vec![bl("_baz"), mov_result, ldp_post(), ret()]]);
346368
         tail_call_opt(&mut mf);
347369
         let insts = &mf.blocks[0].insts;
348370
         // No transformation — Bl should still be present.
349
-        assert!(insts.iter().any(|i| i.opcode == ArmOpcode::Bl),
350
-            "Bl should NOT be removed when result is captured in non-return register");
351
-        assert!(insts.iter().any(|i| i.opcode == ArmOpcode::Ret),
352
-            "Ret should still be present");
371
+        assert!(
372
+            insts.iter().any(|i| i.opcode == ArmOpcode::Bl),
373
+            "Bl should NOT be removed when result is captured in non-return register"
374
+        );
375
+        assert!(
376
+            insts.iter().any(|i| i.opcode == ArmOpcode::Ret),
377
+            "Ret should still be present"
378
+        );
353379
     }
354380
 
355381
     #[test]
@@ -360,9 +386,7 @@ mod tests {
360386
             operands: vec![MachineOperand::BlockRef(MBlockId(1))],
361387
             def: None,
362388
         };
363
-        let mut mf = build_mf(vec![
364
-            vec![bl("_qux"), ldp_post(), b_inst],
365
-        ]);
389
+        let mut mf = build_mf(vec![vec![bl("_qux"), ldp_post(), b_inst]]);
366390
         tail_call_opt(&mut mf);
367391
         // Should still have Bl (TCO not fired because no Ret).
368392
         assert!(mf.blocks[0].insts.iter().any(|i| i.opcode == ArmOpcode::Bl));
src/driver/dep_scan.rsmodified
159 lines changed — click to load
@@ -29,12 +29,15 @@ pub fn scan_file(path: &Path) -> Result<FileDeps, String> {
2929
     for line in content.lines() {
3030
         let trimmed = line.trim().to_lowercase();
3131
         // Skip comments and empty lines.
32
-        if trimmed.starts_with('!') || trimmed.is_empty() { continue; }
32
+        if trimmed.starts_with('!') || trimmed.is_empty() {
33
+            continue;
34
+        }
3335
 
3436
         // MODULE <name> — but not "module procedure" or "module function"
3537
         if let Some(rest) = trimmed.strip_prefix("module ") {
3638
             let rest = rest.trim();
37
-            if rest.starts_with("procedure") || rest.starts_with("function")
39
+            if rest.starts_with("procedure")
40
+                || rest.starts_with("function")
3841
                 || rest.starts_with("subroutine")
3942
             {
4043
                 continue;
@@ -66,7 +69,10 @@ pub fn scan_file(path: &Path) -> Result<FileDeps, String> {
6669
             if rest.starts_with("::") {
6770
                 rest = rest[2..].trim();
6871
             }
69
-            if let Some(name) = rest.split(|c: char| c == ',' || c == ':' || c.is_whitespace()).next() {
72
+            if let Some(name) = rest
73
+                .split(|c: char| c == ',' || c == ':' || c.is_whitespace())
74
+                .next()
75
+            {
7076
                 let clean = name.trim();
7177
                 if !clean.is_empty() && clean != "only" {
7278
                     // Skip intrinsic modules — they don't need .amod files.
@@ -84,13 +90,21 @@ pub fn scan_file(path: &Path) -> Result<FileDeps, String> {
8490
     defines.sort();
8591
     defines.dedup();
8692
 
87
-    Ok(FileDeps { path: path.to_path_buf(), defines, uses })
93
+    Ok(FileDeps {
94
+        path: path.to_path_buf(),
95
+        defines,
96
+        uses,
97
+    })
8898
 }
8999
 
90100
 fn is_intrinsic_module(name: &str) -> bool {
91
-    matches!(name,
92
-        "iso_c_binding" | "iso_fortran_env" |
93
-        "ieee_arithmetic" | "ieee_exceptions" | "ieee_features"
101
+    matches!(
102
+        name,
103
+        "iso_c_binding"
104
+            | "iso_fortran_env"
105
+            | "ieee_arithmetic"
106
+            | "ieee_exceptions"
107
+            | "ieee_features"
94108
     )
95109
 }
96110
 
@@ -148,7 +162,14 @@ pub fn resolve_compilation_order(files: &[FileDeps]) -> Result<Vec<usize>, Strin
148162
         // Cycle detected — find the modules involved.
149163
         let cycle_files: Vec<&str> = (0..n)
150164
             .filter(|i| in_degree[*i] > 0)
151
-            .map(|i| files[i].path.file_name().unwrap_or_default().to_str().unwrap_or("?"))
165
+            .map(|i| {
166
+                files[i]
167
+                    .path
168
+                    .file_name()
169
+                    .unwrap_or_default()
170
+                    .to_str()
171
+                    .unwrap_or("?")
172
+            })
152173
             .collect();
153174
         return Err(format!(
154175
             "circular module dependency detected among: {}",
@@ -168,7 +189,11 @@ mod tests {
168189
         let dir = std::env::temp_dir().join("dep_scan_test_1");
169190
         std::fs::create_dir_all(&dir).unwrap();
170191
         let f = dir.join("mod.f90");
171
-        std::fs::write(&f, "module mymod\n  use other_mod\n  implicit none\nend module\n").unwrap();
192
+        std::fs::write(
193
+            &f,
194
+            "module mymod\n  use other_mod\n  implicit none\nend module\n",
195
+        )
196
+        .unwrap();
172197
         let deps = scan_file(&f).unwrap();
173198
         assert_eq!(deps.defines, vec!["mymod"]);
174199
         assert_eq!(deps.uses, vec!["other_mod"]);
@@ -178,9 +203,21 @@ mod tests {
178203
     #[test]
179204
     fn topo_sort_chain() {
180205
         let files = vec![
181
-            FileDeps { path: "c.f90".into(), defines: vec!["c".into()], uses: vec![] },
182
-            FileDeps { path: "b.f90".into(), defines: vec!["b".into()], uses: vec!["c".into()] },
183
-            FileDeps { path: "a.f90".into(), defines: vec!["a".into()], uses: vec!["b".into()] },
206
+            FileDeps {
207
+                path: "c.f90".into(),
208
+                defines: vec!["c".into()],
209
+                uses: vec![],
210
+            },
211
+            FileDeps {
212
+                path: "b.f90".into(),
213
+                defines: vec!["b".into()],
214
+                uses: vec!["c".into()],
215
+            },
216
+            FileDeps {
217
+                path: "a.f90".into(),
218
+                defines: vec!["a".into()],
219
+                uses: vec!["b".into()],
220
+            },
184221
         ];
185222
         let order = resolve_compilation_order(&files).unwrap();
186223
         // c must come before b, b before a.
@@ -194,20 +231,48 @@ mod tests {
194231
     #[test]
195232
     fn topo_sort_cycle() {
196233
         let files = vec![
197
-            FileDeps { path: "a.f90".into(), defines: vec!["a".into()], uses: vec!["b".into()] },
198
-            FileDeps { path: "b.f90".into(), defines: vec!["b".into()], uses: vec!["a".into()] },
234
+            FileDeps {
235
+                path: "a.f90".into(),
236
+                defines: vec!["a".into()],
237
+                uses: vec!["b".into()],
238
+            },
239
+            FileDeps {
240
+                path: "b.f90".into(),
241
+                defines: vec!["b".into()],
242
+                uses: vec!["a".into()],
243
+            },
199244
         ];
200245
         let err = resolve_compilation_order(&files).unwrap_err();
201
-        assert!(err.contains("circular"), "expected cycle error, got: {}", err);
246
+        assert!(
247
+            err.contains("circular"),
248
+            "expected cycle error, got: {}",
249
+            err
250
+        );
202251
     }
203252
 
204253
     #[test]
205254
     fn topo_sort_diamond() {
206255
         let files = vec![
207
-            FileDeps { path: "d.f90".into(), defines: vec!["d".into()], uses: vec![] },
208
-            FileDeps { path: "b.f90".into(), defines: vec!["b".into()], uses: vec!["d".into()] },
209
-            FileDeps { path: "c.f90".into(), defines: vec!["c".into()], uses: vec!["d".into()] },
210
-            FileDeps { path: "a.f90".into(), defines: vec!["a".into()], uses: vec!["b".into(), "c".into()] },
256
+            FileDeps {
257
+                path: "d.f90".into(),
258
+                defines: vec!["d".into()],
259
+                uses: vec![],
260
+            },
261
+            FileDeps {
262
+                path: "b.f90".into(),
263
+                defines: vec!["b".into()],
264
+                uses: vec!["d".into()],
265
+            },
266
+            FileDeps {
267
+                path: "c.f90".into(),
268
+                defines: vec!["c".into()],
269
+                uses: vec!["d".into()],
270
+            },
271
+            FileDeps {
272
+                path: "a.f90".into(),
273
+                defines: vec!["a".into()],
274
+                uses: vec!["b".into(), "c".into()],
275
+            },
211276
         ];
212277
         let order = resolve_compilation_order(&files).unwrap();
213278
         let pos_d = order.iter().position(|&i| i == 0).unwrap();
src/driver/diag.rsmodified
45 lines changed — click to load
@@ -82,11 +82,16 @@ pub fn render(file: &str, source: &str, span: Span, level: Level, message: &str,
8282
         msg = message,
8383
     );
8484
 
85
-    if let Some((gutter, line_text, caret_indent, caret_len)) =
86
-        snippet_for(source, span, span_len)
85
+    if let Some((gutter, line_text, caret_indent, caret_len)) = snippet_for(source, span, span_len)
8786
     {
8887
         let blue = if color { "\x1b[34m" } else { "" };
89
-        eprintln!("{blue}{gutter:>5} |{reset} {line}", gutter = gutter, reset = reset, blue = blue, line = line_text);
88
+        eprintln!(
89
+            "{blue}{gutter:>5} |{reset} {line}",
90
+            gutter = gutter,
91
+            reset = reset,
92
+            blue = blue,
93
+            line = line_text
94
+        );
9095
         let mut caret = String::new();
9196
         for _ in 0..caret_indent {
9297
             caret.push(' ');
@@ -94,7 +99,13 @@ pub fn render(file: &str, source: &str, span: Span, level: Level, message: &str,
9499
         for _ in 0..caret_len.max(1) {
95100
             caret.push('^');
96101
         }
97
-        eprintln!("{blue}      |{reset} {col_start}{caret}{reset}", blue = blue, reset = reset, col_start = col_start, caret = caret);
102
+        eprintln!(
103
+            "{blue}      |{reset} {col_start}{caret}{reset}",
104
+            blue = blue,
105
+            reset = reset,
106
+            col_start = col_start,
107
+            caret = caret
108
+        );
98109
     }
99110
 }
100111
 
@@ -102,11 +113,7 @@ pub fn render(file: &str, source: &str, span: Span, level: Level, message: &str,
102113
 /// Returns `(line_number, line_text, caret_indent, caret_len)`.
103114
 /// caret_indent is in display columns assuming a tab is replaced by
104115
 /// 4 spaces, matching how the line_text is emitted.
105
-fn snippet_for(
106
-    source: &str,
107
-    span: Span,
108
-    span_len: usize,
109
-) -> Option<(u32, String, usize, usize)> {
116
+fn snippet_for(source: &str, span: Span, span_len: usize) -> Option<(u32, String, usize, usize)> {
110117
     if span.start.line == 0 {
111118
         return None;
112119
     }
src/driver/mod.rsmodified
320 lines changed — click to load
@@ -12,8 +12,8 @@ use std::path::{Path, PathBuf};
1212
 use std::process::Command;
1313
 use std::time::SystemTime;
1414
 
15
-use crate::codegen::{emit, isel, linearscan, peephole};
1615
 use crate::codegen::mir::MachineFunction;
16
+use crate::codegen::{emit, isel, linearscan, peephole};
1717
 use crate::ir::{lower, printer as ir_printer, verify};
1818
 use crate::lexer::{detect_source_form, tokenize, SourceForm};
1919
 use crate::parser::Parser;
@@ -278,7 +278,8 @@ pub fn parse_cli(raw_args: &[String]) -> Result<ParsedCli, String> {
278278
             "-D" => {
279279
                 i += 1;
280280
                 let spec = args.get(i).ok_or("-D requires a macro name")?;
281
-                opts.preprocessor_defines.push(parse_preprocessor_define(spec)?);
281
+                opts.preprocessor_defines
282
+                    .push(parse_preprocessor_define(spec)?);
282283
             }
283284
             arg if arg.starts_with("-D") => {
284285
                 opts.preprocessor_defines
@@ -400,9 +401,7 @@ pub fn parse_cli(raw_args: &[String]) -> Result<ParsedCli, String> {
400401
                 opts.diagnostics_format = match val {
401402
                     "text" => DiagnosticsFormat::Text,
402403
                     "json" => DiagnosticsFormat::Json,
403
-                    other => {
404
-                        return Err(format!("unknown --diagnostics-format value: {}", other))
405
-                    }
404
+                    other => return Err(format!("unknown --diagnostics-format value: {}", other)),
406405
                 };
407406
             }
408407
 
@@ -441,11 +440,17 @@ fn parse_preprocessor_define(spec: &str) -> Result<(String, String), String> {
441440
         None => (spec, "1"),
442441
     };
443442
     if name.is_empty() {
444
-        return Err(format!("invalid macro definition '{}': missing macro name", spec));
443
+        return Err(format!(
444
+            "invalid macro definition '{}': missing macro name",
445
+            spec
446
+        ));
445447
     }
446448
     let mut chars = name.chars();
447449
     let Some(first) = chars.next() else {
448
-        return Err(format!("invalid macro definition '{}': missing macro name", spec));
450
+        return Err(format!(
451
+            "invalid macro definition '{}': missing macro name",
452
+            spec
453
+        ));
449454
     };
450455
     if !(first == '_' || first.is_ascii_alphabetic()) {
451456
         return Err(format!(
@@ -807,7 +812,11 @@ impl PhaseTimer {
807812
         eprintln!("─────────────────────────────────");
808813
         for (name, d) in &self.samples {
809814
             let ms = d.as_secs_f64() * 1000.0;
810
-            let pct = if total_ms > 0.0 { ms / total_ms * 100.0 } else { 0.0 };
815
+            let pct = if total_ms > 0.0 {
816
+                ms / total_ms * 100.0
817
+            } else {
818
+                0.0
819
+            };
811820
             eprintln!("{:<16} {:>8.2} {:>4.0}%", name, ms, pct);
812821
         }
813822
         eprintln!("─────────────────────────────────");
@@ -1013,8 +1022,7 @@ pub fn compile(opts: &Options) -> Result<(), String> {
10131022
         for t in &tokens {
10141023
             buf.push_str(&format!("{:?}\n", t));
10151024
         }
1016
-        fs::write(&out, &buf)
1017
-            .map_err(|e| format!("cannot write '{}': {}", out.display(), e))?;
1025
+        fs::write(&out, &buf).map_err(|e| format!("cannot write '{}': {}", out.display(), e))?;
10181026
         return Ok(());
10191027
     }
10201028
 
@@ -1040,8 +1048,7 @@ pub fn compile(opts: &Options) -> Result<(), String> {
10401048
         for u in &units {
10411049
             buf.push_str(&format!("{:#?}\n", u));
10421050
         }
1043
-        fs::write(&out, &buf)
1044
-            .map_err(|e| format!("cannot write '{}': {}", out.display(), e))?;
1051
+        fs::write(&out, &buf).map_err(|e| format!("cannot write '{}': {}", out.display(), e))?;
10451052
         return Ok(());
10461053
     }
10471054
 
@@ -1085,8 +1092,7 @@ pub fn compile(opts: &Options) -> Result<(), String> {
10851092
         };
10861093
         // span_len is best-effort: end.col >= start.col on the same
10871094
         // line gives a nice underline, otherwise default to 1.
1088
-        let span_len = if d.span.end.line == d.span.start.line
1089
-            && d.span.end.col > d.span.start.col
1095
+        let span_len = if d.span.end.line == d.span.start.line && d.span.end.col > d.span.start.col
10901096
         {
10911097
             (d.span.end.col - d.span.start.col) as usize
10921098
         } else {
@@ -1100,7 +1106,10 @@ pub fn compile(opts: &Options) -> Result<(), String> {
11001106
         }
11011107
     }
11021108
     if had_error {
1103
-        return Err(format!("aborting due to errors in {}", opts.input.display()));
1109
+        return Err(format!(
1110
+            "aborting due to errors in {}",
1111
+            opts.input.display()
1112
+        ));
11041113
     }
11051114
     phase.end(&mut phases);
11061115
     if opts.verbose {
@@ -1114,7 +1123,13 @@ pub fn compile(opts: &Options) -> Result<(), String> {
11141123
         external_char_len_star.extend(crate::sema::amod::extract_char_len_star_params(ext_mod));
11151124
     }
11161125
 
1117
-    let (mut ir_module, module_globals) = lower::lower_file(&units, &st, &type_layouts, external_globals, external_char_len_star);
1126
+    let (mut ir_module, module_globals) = lower::lower_file(
1127
+        &units,
1128
+        &st,
1129
+        &type_layouts,
1130
+        external_globals,
1131
+        external_char_len_star,
1132
+    );
11181133
     let ir_errors = verify::verify_module(&ir_module);
11191134
     if !ir_errors.is_empty() {
11201135
         let msg = ir_errors
@@ -1138,11 +1153,11 @@ pub fn compile(opts: &Options) -> Result<(), String> {
11381153
     {
11391154
         use crate::opt::pipeline::OptLevel as IrOpt;
11401155
         let ir_opt = match opts.opt_level {
1141
-            OptLevel::O0    => IrOpt::O0,
1142
-            OptLevel::O1    => IrOpt::O1,
1143
-            OptLevel::O2    => IrOpt::O2,
1144
-            OptLevel::O3    => IrOpt::O3,
1145
-            OptLevel::Os    => IrOpt::Os,
1156
+            OptLevel::O0 => IrOpt::O0,
1157
+            OptLevel::O1 => IrOpt::O1,
1158
+            OptLevel::O2 => IrOpt::O2,
1159
+            OptLevel::O3 => IrOpt::O3,
1160
+            OptLevel::Os => IrOpt::Os,
11461161
             OptLevel::Ofast => IrOpt::Ofast,
11471162
         };
11481163
         let pm = if ir_module.contains_i128_outside_globals() && opts.opt_level != OptLevel::O0 {
@@ -1172,8 +1187,7 @@ pub fn compile(opts: &Options) -> Result<(), String> {
11721187
 
11731188
     if module_has_i128 && !ir_module.i128_backend_o0_supported() {
11741189
         return Err(
1175
-            "backend does not yet support integer(16) / i128 codegen; use --emit-ir for now"
1176
-                .into(),
1190
+            "backend does not yet support integer(16) / i128 codegen; use --emit-ir for now".into(),
11771191
         );
11781192
     }
11791193
 
@@ -1338,10 +1352,8 @@ _main:
13381352
                         &ir_module,
13391353
                         &std::collections::HashMap::new(), // char_len_star computed by writer from scope
13401354
                     );
1341
-                    let amod_dir: std::path::PathBuf = opts
1342
-                        .module_output_dir
1343
-                        .clone()
1344
-                        .unwrap_or_else(|| {
1355
+                    let amod_dir: std::path::PathBuf =
1356
+                        opts.module_output_dir.clone().unwrap_or_else(|| {
13451357
                             opts.output_path()
13461358
                                 .parent()
13471359
                                 .unwrap_or_else(|| std::path::Path::new("."))
@@ -1465,7 +1477,8 @@ pub fn compile_multi(opts: &Options) -> Result<(), String> {
14651477
     all_inputs.extend(opts.extra_inputs.iter().cloned());
14661478
 
14671479
     // Scan dependencies.
1468
-    let file_deps: Vec<dep_scan::FileDeps> = all_inputs.iter()
1480
+    let file_deps: Vec<dep_scan::FileDeps> = all_inputs
1481
+        .iter()
14691482
         .map(|p| dep_scan::scan_file(p))
14701483
         .collect::<Result<Vec<_>, _>>()?;
14711484
 
@@ -1474,13 +1487,16 @@ pub fn compile_multi(opts: &Options) -> Result<(), String> {
14741487
 
14751488
     // Compile each file in order.
14761489
     let tmp_dir = std::env::temp_dir().join(format!("afs_multi_{}", std::process::id()));
1477
-    fs::create_dir_all(&tmp_dir)
1478
-        .map_err(|e| format!("cannot create temp dir: {}", e))?;
1490
+    fs::create_dir_all(&tmp_dir).map_err(|e| format!("cannot create temp dir: {}", e))?;
14791491
 
14801492
     let mut object_files: Vec<PathBuf> = Vec::new();
14811493
     for &idx in &order {
14821494
         let src = &file_deps[idx].path;
1483
-        let stem = src.file_stem().unwrap_or_default().to_str().unwrap_or("out");
1495
+        let stem = src
1496
+            .file_stem()
1497
+            .unwrap_or_default()
1498
+            .to_str()
1499
+            .unwrap_or("out");
14841500
         let obj_path = tmp_dir.join(format!("{}.o", stem));
14851501
 
14861502
         // Build a single-file Options for this source by inheriting
@@ -1524,7 +1540,10 @@ pub fn compile_multi(opts: &Options) -> Result<(), String> {
15241540
     }
15251541
 
15261542
     // Link all object files.
1527
-    let output = opts.output.clone().unwrap_or_else(|| PathBuf::from("a.out"));
1543
+    let output = opts
1544
+        .output
1545
+        .clone()
1546
+        .unwrap_or_else(|| PathBuf::from("a.out"));
15281547
     link_multi(&object_files, &output, opts)?;
15291548
 
15301549
     // Cleanup.
@@ -1592,13 +1611,11 @@ fn find_runtime_lib() -> Result<String, String> {
15921611
         }
15931612
     }
15941613
 
1595
-    Err(
1596
-        "cannot find libarmfortas_rt.a. Searched: \
1614
+    Err("cannot find libarmfortas_rt.a. Searched: \
15971615
          $AFS_RUNTIME_PATH, cargo workspace, next to the compiler \
15981616
          binary, and /usr/local/lib. Build with \
15991617
          'cargo build -p armfortas-rt' or set AFS_RUNTIME_PATH."
1600
-            .into(),
1601
-    )
1618
+        .into())
16021619
 }
16031620
 
16041621
 fn maybe_refresh_runtime_lib(workspace_root: &Path) -> Result<(), String> {
@@ -1611,7 +1628,9 @@ fn maybe_refresh_runtime_lib(workspace_root: &Path) -> Result<(), String> {
16111628
         return Ok(());
16121629
     };
16131630
     let debug_archive = workspace_root.join("target/debug/libarmfortas_rt.a");
1614
-    let archive_mtime = fs::metadata(&debug_archive).ok().and_then(|meta| meta.modified().ok());
1631
+    let archive_mtime = fs::metadata(&debug_archive)
1632
+        .ok()
1633
+        .and_then(|meta| meta.modified().ok());
16151634
 
16161635
     if archive_mtime.is_some_and(|mtime| mtime >= source_mtime) {
16171636
         return Ok(());
@@ -1661,7 +1680,8 @@ fn find_workspace_root() -> Option<PathBuf> {
16611680
 
16621681
     for base in bases {
16631682
         for ancestor in base.ancestors() {
1664
-            if ancestor.join("Cargo.toml").exists() && ancestor.join("runtime/Cargo.toml").exists() {
1683
+            if ancestor.join("Cargo.toml").exists() && ancestor.join("runtime/Cargo.toml").exists()
1684
+            {
16651685
                 return Some(ancestor.to_path_buf());
16661686
             }
16671687
         }
@@ -1744,7 +1764,11 @@ mod tests {
17441764
 
17451765
         compile(&opts).expect("O0 --emit-ir should support integer(16) staging");
17461766
         let ir = fs::read_to_string(&output).expect("missing emitted IR");
1747
-        assert!(ir.contains("i128"), "emitted IR should expose integer(16) as i128:\n{}", ir);
1767
+        assert!(
1768
+            ir.contains("i128"),
1769
+            "emitted IR should expose integer(16) as i128:\n{}",
1770
+            ir
1771
+        );
17481772
         let _ = fs::remove_file(output);
17491773
     }
17501774
 
@@ -1768,7 +1792,8 @@ mod tests {
17681792
             ..Options::default()
17691793
         };
17701794
 
1771
-        let err = compile(&opts).expect_err("backend should reject integer(16) until i128 codegen lands");
1795
+        let err =
1796
+            compile(&opts).expect_err("backend should reject integer(16) until i128 codegen lands");
17721797
         assert!(
17731798
             err.contains("backend does not yet support integer(16) / i128 codegen"),
17741799
             "unexpected backend rejection:\n{}",
@@ -1798,7 +1823,11 @@ mod tests {
17981823
 
17991824
         compile(&opts).expect("simple integer(16) memory traffic should codegen at O0");
18001825
         let asm = fs::read_to_string(&output).expect("missing emitted assembly");
1801
-        assert!(asm.contains("stp x16, x17"), "expected paired i128 store in asm:\n{}", asm);
1826
+        assert!(
1827
+            asm.contains("stp x16, x17"),
1828
+            "expected paired i128 store in asm:\n{}",
1829
+            asm
1830
+        );
18021831
         let _ = fs::remove_file(output);
18031832
     }
18041833
 
@@ -1824,7 +1853,11 @@ mod tests {
18241853
 
18251854
         compile(&opts).expect("simple integer(16) add should codegen at O0");
18261855
         let asm = fs::read_to_string(&output).expect("missing emitted assembly");
1827
-        assert!(asm.contains("adds x16, x16, x8"), "expected i128 add carry chain in asm:\n{}", asm);
1856
+        assert!(
1857
+            asm.contains("adds x16, x16, x8"),
1858
+            "expected i128 add carry chain in asm:\n{}",
1859
+            asm
1860
+        );
18281861
         let _ = fs::remove_file(output);
18291862
     }
18301863
 
@@ -1850,8 +1883,16 @@ mod tests {
18501883
 
18511884
         compile(&opts).expect("internal integer(16) call should codegen at O0");
18521885
         let asm = fs::read_to_string(&output).expect("missing emitted assembly");
1853
-        assert!(asm.contains("bl _add_one"), "expected internal helper call in asm:\n{}", asm);
1854
-        assert!(asm.contains("stp x0, x1"), "expected pair-register i128 ABI spill in asm:\n{}", asm);
1886
+        assert!(
1887
+            asm.contains("bl _add_one"),
1888
+            "expected internal helper call in asm:\n{}",
1889
+            asm
1890
+        );
1891
+        assert!(
1892
+            asm.contains("stp x0, x1"),
1893
+            "expected pair-register i128 ABI spill in asm:\n{}",
1894
+            asm
1895
+        );
18551896
         let _ = fs::remove_file(output);
18561897
     }
18571898
 
@@ -1877,8 +1918,16 @@ mod tests {
18771918
 
18781919
         compile(&opts).expect("external integer(16) call should codegen at O0");
18791920
         let asm = fs::read_to_string(&output).expect("missing emitted assembly");
1880
-        assert!(asm.contains("bl _add_ext"), "expected external helper call in asm:\n{}", asm);
1881
-        assert!(asm.contains("stp x0, x1"), "expected pair-register i128 ABI spill in asm:\n{}", asm);
1921
+        assert!(
1922
+            asm.contains("bl _add_ext"),
1923
+            "expected external helper call in asm:\n{}",
1924
+            asm
1925
+        );
1926
+        assert!(
1927
+            asm.contains("stp x0, x1"),
1928
+            "expected pair-register i128 ABI spill in asm:\n{}",
1929
+            asm
1930
+        );
18821931
         let _ = fs::remove_file(output);
18831932
     }
18841933
 
@@ -1904,8 +1953,16 @@ mod tests {
19041953
 
19051954
         compile(&opts).expect("integer(16) multiply should codegen at O1 after const fold");
19061955
         let asm = fs::read_to_string(&output).expect("missing emitted assembly");
1907
-        assert!(asm.contains("movz x16, #42"), "expected folded i128 constant in asm:\n{}", asm);
1908
-        assert!(!asm.contains("mul "), "expected O1 i128 multiply to fold away before backend:\n{}", asm);
1956
+        assert!(
1957
+            asm.contains("movz x16, #42"),
1958
+            "expected folded i128 constant in asm:\n{}",
1959
+            asm
1960
+        );
1961
+        assert!(
1962
+            !asm.contains("mul "),
1963
+            "expected O1 i128 multiply to fold away before backend:\n{}",
1964
+            asm
1965
+        );
19091966
         let _ = fs::remove_file(output);
19101967
     }
19111968
 
src/ir/builder.rsmodified
348 lines changed — click to load
@@ -3,9 +3,9 @@
33
 //! Used by the AST→IR lowering pass and by tests. Manages ValueId
44
 //! allocation, block insertion, and instruction emission.
55
 
6
-use crate::lexer::{Span, Position};
7
-use super::types::*;
86
 use super::inst::*;
7
+use super::types::*;
8
+use crate::lexer::{Position, Span};
99
 
1010
 /// Builder for constructing a function's IR.
1111
 pub struct FuncBuilder<'a> {
@@ -16,7 +16,10 @@ pub struct FuncBuilder<'a> {
1616
 impl<'a> FuncBuilder<'a> {
1717
     pub fn new(func: &'a mut Function) -> Self {
1818
         let entry = func.entry;
19
-        Self { func, current_block: entry }
19
+        Self {
20
+            func,
21
+            current_block: entry,
22
+        }
2023
     }
2124
 
2225
     /// Switch to emitting into a different block.
@@ -38,19 +41,29 @@ impl<'a> FuncBuilder<'a> {
3841
     pub fn add_block_param(&mut self, block: BlockId, ty: IrType) -> ValueId {
3942
         let id = self.func.next_value_id();
4043
         self.func.register_type(id, ty.clone());
41
-        self.func.block_mut(block).params.push(BlockParam { id, ty });
44
+        self.func
45
+            .block_mut(block)
46
+            .params
47
+            .push(BlockParam { id, ty });
4248
         id
4349
     }
4450
 
4551
     /// Get the underlying function.
46
-    pub fn func(&self) -> &Function { self.func }
52
+    pub fn func(&self) -> &Function {
53
+        self.func
54
+    }
4755
 
4856
     // ---- Instruction emission ----
4957
 
5058
     fn emit(&mut self, kind: InstKind, ty: IrType) -> ValueId {
5159
         let id = self.func.next_value_id();
5260
         self.func.register_type(id, ty.clone());
53
-        let inst = Inst { id, kind, ty, span: dummy_span() };
61
+        let inst = Inst {
62
+            id,
63
+            kind,
64
+            ty,
65
+            span: dummy_span(),
66
+        };
5467
         self.func.block_mut(self.current_block).insts.push(inst);
5568
         id
5669
     }
@@ -110,74 +123,116 @@ impl<'a> FuncBuilder<'a> {
110123
     // ---- Integer arithmetic ----
111124
 
112125
     pub fn iadd(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
113
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
126
+        let ty = self
127
+            .func
128
+            .value_type(lhs)
129
+            .unwrap_or(IrType::Int(IntWidth::I32));
114130
         self.emit(InstKind::IAdd(lhs, rhs), ty)
115131
     }
116132
 
117133
     pub fn isub(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
118
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
134
+        let ty = self
135
+            .func
136
+            .value_type(lhs)
137
+            .unwrap_or(IrType::Int(IntWidth::I32));
119138
         self.emit(InstKind::ISub(lhs, rhs), ty)
120139
     }
121140
 
122141
     pub fn imul(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
123
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
142
+        let ty = self
143
+            .func
144
+            .value_type(lhs)
145
+            .unwrap_or(IrType::Int(IntWidth::I32));
124146
         self.emit(InstKind::IMul(lhs, rhs), ty)
125147
     }
126148
 
127149
     pub fn idiv(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
128
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
150
+        let ty = self
151
+            .func
152
+            .value_type(lhs)
153
+            .unwrap_or(IrType::Int(IntWidth::I32));
129154
         self.emit(InstKind::IDiv(lhs, rhs), ty)
130155
     }
131156
 
132157
     pub fn imod(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
133
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
158
+        let ty = self
159
+            .func
160
+            .value_type(lhs)
161
+            .unwrap_or(IrType::Int(IntWidth::I32));
134162
         self.emit(InstKind::IMod(lhs, rhs), ty)
135163
     }
136164
 
137165
     pub fn ineg(&mut self, val: ValueId) -> ValueId {
138
-        let ty = self.func.value_type(val).unwrap_or(IrType::Int(IntWidth::I32));
166
+        let ty = self
167
+            .func
168
+            .value_type(val)
169
+            .unwrap_or(IrType::Int(IntWidth::I32));
139170
         self.emit(InstKind::INeg(val), ty)
140171
     }
141172
 
142173
     // ---- Float arithmetic ----
143174
 
144175
     pub fn fadd(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
145
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Float(FloatWidth::F32));
176
+        let ty = self
177
+            .func
178
+            .value_type(lhs)
179
+            .unwrap_or(IrType::Float(FloatWidth::F32));
146180
         self.emit(InstKind::FAdd(lhs, rhs), ty)
147181
     }
148182
 
149183
     pub fn fsub(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
150
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Float(FloatWidth::F32));
184
+        let ty = self
185
+            .func
186
+            .value_type(lhs)
187
+            .unwrap_or(IrType::Float(FloatWidth::F32));
151188
         self.emit(InstKind::FSub(lhs, rhs), ty)
152189
     }
153190
 
154191
     pub fn fmul(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
155
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Float(FloatWidth::F32));
192
+        let ty = self
193
+            .func
194
+            .value_type(lhs)
195
+            .unwrap_or(IrType::Float(FloatWidth::F32));
156196
         self.emit(InstKind::FMul(lhs, rhs), ty)
157197
     }
158198
 
159199
     pub fn fdiv(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
160
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Float(FloatWidth::F32));
200
+        let ty = self
201
+            .func
202
+            .value_type(lhs)
203
+            .unwrap_or(IrType::Float(FloatWidth::F32));
161204
         self.emit(InstKind::FDiv(lhs, rhs), ty)
162205
     }
163206
 
164207
     pub fn fneg(&mut self, val: ValueId) -> ValueId {
165
-        let ty = self.func.value_type(val).unwrap_or(IrType::Float(FloatWidth::F32));
208
+        let ty = self
209
+            .func
210
+            .value_type(val)
211
+            .unwrap_or(IrType::Float(FloatWidth::F32));
166212
         self.emit(InstKind::FNeg(val), ty)
167213
     }
168214
 
169215
     pub fn fabs(&mut self, val: ValueId) -> ValueId {
170
-        let ty = self.func.value_type(val).unwrap_or(IrType::Float(FloatWidth::F64));
216
+        let ty = self
217
+            .func
218
+            .value_type(val)
219
+            .unwrap_or(IrType::Float(FloatWidth::F64));
171220
         self.emit(InstKind::FAbs(val), ty)
172221
     }
173222
 
174223
     pub fn fsqrt(&mut self, val: ValueId) -> ValueId {
175
-        let ty = self.func.value_type(val).unwrap_or(IrType::Float(FloatWidth::F64));
224
+        let ty = self
225
+            .func
226
+            .value_type(val)
227
+            .unwrap_or(IrType::Float(FloatWidth::F64));
176228
         self.emit(InstKind::FSqrt(val), ty)
177229
     }
178230
 
179231
     pub fn fpow(&mut self, base: ValueId, exp: ValueId) -> ValueId {
180
-        let ty = self.func.value_type(base).unwrap_or(IrType::Float(FloatWidth::F64));
232
+        let ty = self
233
+            .func
234
+            .value_type(base)
235
+            .unwrap_or(IrType::Float(FloatWidth::F64));
181236
         self.emit(InstKind::FPow(base, exp), ty)
182237
     }
183238
 
@@ -195,7 +250,10 @@ impl<'a> FuncBuilder<'a> {
195250
 
196251
     /// Conditional select: cond ? true_val : false_val
197252
     pub fn select(&mut self, cond: ValueId, true_val: ValueId, false_val: ValueId) -> ValueId {
198
-        let ty = self.func.value_type(true_val).unwrap_or(IrType::Int(IntWidth::I32));
253
+        let ty = self
254
+            .func
255
+            .value_type(true_val)
256
+            .unwrap_or(IrType::Int(IntWidth::I32));
199257
         self.emit(InstKind::Select(cond, true_val, false_val), ty)
200258
     }
201259
 
@@ -216,47 +274,74 @@ impl<'a> FuncBuilder<'a> {
216274
     // ---- Bitwise ----
217275
 
218276
     pub fn bit_and(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
219
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
277
+        let ty = self
278
+            .func
279
+            .value_type(lhs)
280
+            .unwrap_or(IrType::Int(IntWidth::I32));
220281
         self.emit(InstKind::BitAnd(lhs, rhs), ty)
221282
     }
222283
 
223284
     pub fn bit_or(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
224
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
285
+        let ty = self
286
+            .func
287
+            .value_type(lhs)
288
+            .unwrap_or(IrType::Int(IntWidth::I32));
225289
         self.emit(InstKind::BitOr(lhs, rhs), ty)
226290
     }
227291
 
228292
     pub fn bit_xor(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
229
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
293
+        let ty = self
294
+            .func
295
+            .value_type(lhs)
296
+            .unwrap_or(IrType::Int(IntWidth::I32));
230297
         self.emit(InstKind::BitXor(lhs, rhs), ty)
231298
     }
232299
 
233300
     pub fn shl(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
234
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
301
+        let ty = self
302
+            .func
303
+            .value_type(lhs)
304
+            .unwrap_or(IrType::Int(IntWidth::I32));
235305
         self.emit(InstKind::Shl(lhs, rhs), ty)
236306
     }
237307
 
238308
     pub fn bit_not(&mut self, val: ValueId) -> ValueId {
239
-        let ty = self.func.value_type(val).unwrap_or(IrType::Int(IntWidth::I32));
309
+        let ty = self
310
+            .func
311
+            .value_type(val)
312
+            .unwrap_or(IrType::Int(IntWidth::I32));
240313
         self.emit(InstKind::BitNot(val), ty)
241314
     }
242315
 
243316
     pub fn lshr(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
244
-        let ty = self.func.value_type(lhs).unwrap_or(IrType::Int(IntWidth::I32));
317
+        let ty = self
318
+            .func
319
+            .value_type(lhs)
320
+            .unwrap_or(IrType::Int(IntWidth::I32));
245321
         self.emit(InstKind::LShr(lhs, rhs), ty)
246322
     }
247323
 
248324
     pub fn clz(&mut self, val: ValueId) -> ValueId {
249
-        let ty = self.func.value_type(val).unwrap_or(IrType::Int(IntWidth::I32));
325
+        let ty = self
326
+            .func
327
+            .value_type(val)
328
+            .unwrap_or(IrType::Int(IntWidth::I32));
250329
         self.emit(InstKind::CountLeadingZeros(val), ty)
251330
     }
252331
 
253332
     pub fn ctz(&mut self, val: ValueId) -> ValueId {
254
-        let ty = self.func.value_type(val).unwrap_or(IrType::Int(IntWidth::I32));
333
+        let ty = self
334
+            .func
335
+            .value_type(val)
336
+            .unwrap_or(IrType::Int(IntWidth::I32));
255337
         self.emit(InstKind::CountTrailingZeros(val), ty)
256338
     }
257339
 
258340
     pub fn popcount(&mut self, val: ValueId) -> ValueId {
259
-        let ty = self.func.value_type(val).unwrap_or(IrType::Int(IntWidth::I32));
341
+        let ty = self
342
+            .func
343
+            .value_type(val)
344
+            .unwrap_or(IrType::Int(IntWidth::I32));
260345
         self.emit(InstKind::PopCount(val), ty)
261346
     }
262347
 
@@ -330,7 +415,10 @@ impl<'a> FuncBuilder<'a> {
330415
     }
331416
 
332417
     pub fn gep(&mut self, base: ValueId, indices: Vec<ValueId>, result_ty: IrType) -> ValueId {
333
-        self.emit(InstKind::GetElementPtr(base, indices), IrType::Ptr(Box::new(result_ty)))
418
+        self.emit(
419
+            InstKind::GetElementPtr(base, indices),
420
+            IrType::Ptr(Box::new(result_ty)),
421
+        )
334422
     }
335423
 
336424
     // ---- Calls ----
@@ -339,7 +427,12 @@ impl<'a> FuncBuilder<'a> {
339427
         self.emit(InstKind::Call(func_ref, args), ret_ty)
340428
     }
341429
 
342
-    pub fn runtime_call(&mut self, func: RuntimeFunc, args: Vec<ValueId>, ret_ty: IrType) -> ValueId {
430
+    pub fn runtime_call(
431
+        &mut self,
432
+        func: RuntimeFunc,
433
+        args: Vec<ValueId>,
434
+        ret_ty: IrType,
435
+    ) -> ValueId {
343436
         self.emit(InstKind::RuntimeCall(func, args), ret_ty)
344437
     }
345438
 
@@ -365,8 +458,7 @@ impl<'a> FuncBuilder<'a> {
365458
     }
366459
 
367460
     pub fn branch(&mut self, dest: BlockId, args: Vec<ValueId>) {
368
-        self.func.block_mut(self.current_block).terminator =
369
-            Some(Terminator::Branch(dest, args));
461
+        self.func.block_mut(self.current_block).terminator = Some(Terminator::Branch(dest, args));
370462
     }
371463
 
372464
     pub fn cond_branch(
@@ -377,13 +469,21 @@ impl<'a> FuncBuilder<'a> {
377469
         false_dest: BlockId,
378470
         false_args: Vec<ValueId>,
379471
     ) {
380
-        self.func.block_mut(self.current_block).terminator =
381
-            Some(Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args });
472
+        self.func.block_mut(self.current_block).terminator = Some(Terminator::CondBranch {
473
+            cond,
474
+            true_dest,
475
+            true_args,
476
+            false_dest,
477
+            false_args,
478
+        });
382479
     }
383480
 
384481
     pub fn switch(&mut self, selector: ValueId, cases: Vec<(i64, BlockId)>, default: BlockId) {
385
-        self.func.block_mut(self.current_block).terminator =
386
-            Some(Terminator::Switch { selector, cases, default });
482
+        self.func.block_mut(self.current_block).terminator = Some(Terminator::Switch {
483
+            selector,
484
+            cases,
485
+            default,
486
+        });
387487
     }
388488
 
389489
     pub fn unreachable(&mut self) {
@@ -403,7 +503,11 @@ impl<'a> FuncBuilder<'a> {
403503
 }
404504
 
405505
 fn dummy_span() -> Span {
406
-    Span { file_id: 0, start: Position { line: 0, col: 0 }, end: Position { line: 0, col: 0 } }
506
+    Span {
507
+        file_id: 0,
508
+        start: Position { line: 0, col: 0 },
509
+        end: Position { line: 0, col: 0 },
510
+    }
407511
 }
408512
 
409513
 #[cfg(test)]
src/ir/inst.rsmodified
224 lines changed — click to load
@@ -3,7 +3,7 @@
33
 //! Every instruction produces a value (ValueId) in SSA form.
44
 //! Basic blocks end with exactly one Terminator.
55
 
6
-use super::types::{IrType, IntWidth, FloatWidth};
6
+use super::types::{FloatWidth, IntWidth, IrType};
77
 use crate::lexer::Span;
88
 use std::collections::HashMap;
99
 
@@ -125,7 +125,7 @@ pub enum InstKind {
125125
     FloatToInt(ValueId, IntWidth),
126126
     FloatExtend(ValueId, FloatWidth),
127127
     FloatTrunc(ValueId, FloatWidth),
128
-    IntExtend(ValueId, IntWidth, bool),   // bool = signed
128
+    IntExtend(ValueId, IntWidth, bool), // bool = signed
129129
     IntTrunc(ValueId, IntWidth),
130130
     /// Convert a pointer to an integer (address as i64).
131131
     PtrToInt(ValueId),
@@ -283,12 +283,18 @@ impl Function {
283283
     /// Get a block by ID. Panics if the ID is not present — use
284284
     /// `try_block` for graceful degradation.
285285
     pub fn block(&self, id: BlockId) -> &BasicBlock {
286
-        self.blocks.iter().find(|b| b.id == id).expect("block not found")
286
+        self.blocks
287
+            .iter()
288
+            .find(|b| b.id == id)
289
+            .expect("block not found")
287290
     }
288291
 
289292
     /// Get a mutable block by ID. Panics if the ID is not present.
290293
     pub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock {
291
-        self.blocks.iter_mut().find(|b| b.id == id).expect("block not found")
294
+        self.blocks
295
+            .iter_mut()
296
+            .find(|b| b.id == id)
297
+            .expect("block not found")
292298
     }
293299
 
294300
     /// Get a block by ID, returning `None` if the ID is not
@@ -337,14 +343,20 @@ impl Function {
337343
         // pointer-type bugs for entire compilation units. Recompute
338344
         // on-demand so consumers always get a consistent answer.
339345
         for p in &self.params {
340
-            if p.id == id { return Some(p.ty.clone()); }
346
+            if p.id == id {
347
+                return Some(p.ty.clone());
348
+            }
341349
         }
342350
         for block in &self.blocks {
343351
             for bp in &block.params {
344
-                if bp.id == id { return Some(bp.ty.clone()); }
352
+                if bp.id == id {
353
+                    return Some(bp.ty.clone());
354
+                }
345355
             }
346356
             for inst in &block.insts {
347
-                if inst.id == id { return Some(inst.ty.clone()); }
357
+                if inst.id == id {
358
+                    return Some(inst.ty.clone());
359
+                }
348360
             }
349361
         }
350362
         None
@@ -354,7 +366,9 @@ impl Function {
354366
     pub fn find_defining_inst(&self, id: ValueId) -> Option<&Inst> {
355367
         for block in &self.blocks {
356368
             for inst in &block.insts {
357
-                if inst.id == id { return Some(inst); }
369
+                if inst.id == id {
370
+                    return Some(inst);
371
+                }
358372
             }
359373
         }
360374
         None
@@ -435,14 +449,28 @@ impl Module {
435449
 
436450
     /// True when any live IR surface in the module uses `i128`.
437451
     pub fn contains_i128(&self) -> bool {
438
-        self.globals.iter().any(|global| type_contains_i128(self, &global.ty))
439
-            || self.extern_funcs.iter().any(|func| sig_contains_i128(self, &func.sig))
452
+        self.globals
453
+            .iter()
454
+            .any(|global| type_contains_i128(self, &global.ty))
455
+            || self
456
+                .extern_funcs
457
+                .iter()
458
+                .any(|func| sig_contains_i128(self, &func.sig))
440459
             || self.functions.iter().any(|func| {
441460
                 type_contains_i128(self, &func.return_type)
442
-                    || func.params.iter().any(|param| type_contains_i128(self, &param.ty))
461
+                    || func
462
+                        .params
463
+                        .iter()
464
+                        .any(|param| type_contains_i128(self, &param.ty))
443465
                     || func.blocks.iter().any(|block| {
444
-                        block.params.iter().any(|param| type_contains_i128(self, &param.ty))
445
-                            || block.insts.iter().any(|inst| type_contains_i128(self, &inst.ty))
466
+                        block
467
+                            .params
468
+                            .iter()
469
+                            .any(|param| type_contains_i128(self, &param.ty))
470
+                            || block
471
+                                .insts
472
+                                .iter()
473
+                                .any(|inst| type_contains_i128(self, &inst.ty))
446474
                     })
447475
             })
448476
     }
@@ -454,13 +482,24 @@ impl Module {
454482
     /// Parameters, returns, instruction results, block params, and extern
455483
     /// signatures still imply unsupported ABI or codegen work.
456484
     pub fn contains_i128_outside_globals(&self) -> bool {
457
-        self.extern_funcs.iter().any(|func| sig_contains_i128(self, &func.sig))
485
+        self.extern_funcs
486
+            .iter()
487
+            .any(|func| sig_contains_i128(self, &func.sig))
458488
             || self.functions.iter().any(|func| {
459489
                 type_contains_i128(self, &func.return_type)
460
-                    || func.params.iter().any(|param| type_contains_i128(self, &param.ty))
490
+                    || func
491
+                        .params
492
+                        .iter()
493
+                        .any(|param| type_contains_i128(self, &param.ty))
461494
                     || func.blocks.iter().any(|block| {
462
-                        block.params.iter().any(|param| type_contains_i128(self, &param.ty))
463
-                            || block.insts.iter().any(|inst| type_contains_i128(self, &inst.ty))
495
+                        block
496
+                            .params
497
+                            .iter()
498
+                            .any(|param| type_contains_i128(self, &param.ty))
499
+                            || block
500
+                                .insts
501
+                                .iter()
502
+                                .any(|inst| type_contains_i128(self, &inst.ty))
464503
                     })
465504
             })
466505
     }
@@ -494,17 +533,14 @@ impl Module {
494533
         self.globals
495534
             .iter()
496535
             .all(|global| global_i128_backend_data_supported(self, global))
497
-            && self
498
-                .extern_funcs
499
-                .iter()
500
-                .all(|func| {
501
-                    abi_type_i128_backend_o0_supported(self, &func.sig.ret, true)
502
-                        && func
503
-                            .sig
504
-                            .params
505
-                            .iter()
506
-                            .all(|param| abi_type_i128_backend_o0_supported(self, param, true))
507
-                })
536
+            && self.extern_funcs.iter().all(|func| {
537
+                abi_type_i128_backend_o0_supported(self, &func.sig.ret, true)
538
+                    && func
539
+                        .sig
540
+                        .params
541
+                        .iter()
542
+                        .all(|param| abi_type_i128_backend_o0_supported(self, param, true))
543
+            })
508544
             && self
509545
                 .functions
510546
                 .iter()
@@ -514,17 +550,21 @@ impl Module {
514550
 
515551
 fn sig_contains_i128(module: &Module, sig: &super::types::FuncSig) -> bool {
516552
     type_contains_i128(module, &sig.ret)
517
-        || sig.params.iter().any(|param| type_contains_i128(module, param))
553
+        || sig
554
+            .params
555
+            .iter()
556
+            .any(|param| type_contains_i128(module, param))
518557
 }
519558
 
520559
 fn type_contains_i128(module: &Module, ty: &IrType) -> bool {
521560
     match ty {
522561
         IrType::Int(IntWidth::I128) => true,
523562
         IrType::Ptr(inner) | IrType::Array(inner, _) => type_contains_i128(module, inner),
524
-        IrType::Struct(id) => module
525
-            .struct_defs
526
-            .get(*id as usize)
527
-            .is_some_and(|def| def.fields.iter().any(|(_, field_ty)| type_contains_i128(module, field_ty))),
563
+        IrType::Struct(id) => module.struct_defs.get(*id as usize).is_some_and(|def| {
564
+            def.fields
565
+                .iter()
566
+                .any(|(_, field_ty)| type_contains_i128(module, field_ty))
567
+        }),
528568
         IrType::FuncPtr(sig) => sig_contains_i128(module, sig),
529569
         _ => false,
530570
     }
@@ -586,12 +626,14 @@ fn runtime_call_i128_backend_o0_supported(
586626
     result_ty: &IrType,
587627
 ) -> bool {
588628
     match rf {
589
-        RuntimeFunc::PrintInt => matches!(result_ty, IrType::Void)
590
-            && args.len() == 1
591
-            && args
592
-                .iter()
593
-                .filter_map(|arg| func.value_type(*arg))
594
-                .all(|ty| abi_type_i128_backend_o0_supported(module, &ty, true)),
629
+        RuntimeFunc::PrintInt => {
630
+            matches!(result_ty, IrType::Void)
631
+                && args.len() == 1
632
+                && args
633
+                    .iter()
634
+                    .filter_map(|arg| func.value_type(*arg))
635
+                    .all(|ty| abi_type_i128_backend_o0_supported(module, &ty, true))
636
+        }
595637
         _ => false,
596638
     }
597639
 }
@@ -640,7 +682,10 @@ fn inst_i128_backend_o0_supported(module: &Module, func: &Function, inst: &Inst)
640682
         // dereferencing an sret-style hidden result-buffer pointer.
641683
         InstKind::Load(_) if matches!(inst.ty, IrType::Ptr(_)) => true,
642684
         InstKind::IAdd(..) | InstKind::ISub(..) | InstKind::INeg(_)
643
-            if matches!(inst.ty, IrType::Int(IntWidth::I128)) => true,
685
+            if matches!(inst.ty, IrType::Int(IntWidth::I128)) =>
686
+        {
687
+            true
688
+        }
644689
         InstKind::ICmp(..) if uses_i128 => true,
645690
         InstKind::Select(..) if matches!(inst.ty, IrType::Int(IntWidth::I128)) => true,
646691
         InstKind::Call(callee, args) if inst_ty_has_i128 || uses_i128 => {
@@ -678,7 +723,11 @@ fn terminator_i128_backend_o0_supported(
678723
             .iter()
679724
             .filter_map(|arg| func.value_type(*arg))
680725
             .all(|ty| ssa_type_i128_backend_o0_supported(module, &ty)),
681
-        Terminator::CondBranch { true_args, false_args, .. } => true_args
726
+        Terminator::CondBranch {
727
+            true_args,
728
+            false_args,
729
+            ..
730
+        } => true_args
682731
             .iter()
683732
             .chain(false_args.iter())
684733
             .filter_map(|arg| func.value_type(*arg))
src/ir/mod.rsmodified
13 lines changed — click to load
@@ -4,10 +4,10 @@
44
 //! Fortran-aware: understands array descriptors, string descriptors,
55
 //! and allocatable semantics.
66
 
7
-pub mod types;
8
-pub mod inst;
97
 pub mod builder;
8
+pub mod inst;
9
+pub mod lower;
1010
 pub mod printer;
11
+pub mod types;
1112
 pub mod verify;
1213
 pub mod walk;
13
-pub mod lower;
src/ir/printer.rsmodified
293 lines changed — click to load
@@ -2,8 +2,8 @@
22
 //!
33
 //! Used by `-emit-ir` and in test assertions.
44
 
5
-use std::fmt::Write;
65
 use super::inst::*;
6
+use std::fmt::Write;
77
 
88
 /// Print a module to a string.
99
 pub fn print_module(module: &Module) -> String {
@@ -13,7 +13,9 @@ pub fn print_module(module: &Module) -> String {
1313
     for sd in &module.struct_defs {
1414
         write!(out, "  struct {} {{ ", sd.name).unwrap();
1515
         for (i, (name, ty)) in sd.fields.iter().enumerate() {
16
-            if i > 0 { write!(out, ", ").unwrap(); }
16
+            if i > 0 {
17
+                write!(out, ", ").unwrap();
18
+            }
1719
             write!(out, "{}: {}", name, ty).unwrap();
1820
         }
1921
         writeln!(out, " }}").unwrap();
@@ -26,7 +28,9 @@ pub fn print_module(module: &Module) -> String {
2628
                 GlobalInit::Zero => write!(out, " = zeroinit").unwrap(),
2729
                 GlobalInit::Int(v) => write!(out, " = {}", v).unwrap(),
2830
                 GlobalInit::Float(v) => write!(out, " = {}", v).unwrap(),
29
-                GlobalInit::String(s) => write!(out, " = {:?}", String::from_utf8_lossy(s)).unwrap(),
31
+                GlobalInit::String(s) => {
32
+                    write!(out, " = {:?}", String::from_utf8_lossy(s)).unwrap()
33
+                }
3034
                 GlobalInit::IntArray(vs) => {
3135
                     let s: Vec<String> = vs.iter().map(|v| v.to_string()).collect();
3236
                     write!(out, " = [{}]", s.join(", ")).unwrap();
@@ -43,7 +47,9 @@ pub fn print_module(module: &Module) -> String {
4347
     for ef in &module.extern_funcs {
4448
         write!(out, "  extern fn @{}(", ef.name).unwrap();
4549
         for (i, p) in ef.sig.params.iter().enumerate() {
46
-            if i > 0 { write!(out, ", ").unwrap(); }
50
+            if i > 0 {
51
+                write!(out, ", ").unwrap();
52
+            }
4753
             write!(out, "{}", p).unwrap();
4854
         }
4955
         writeln!(out, ") -> {}", ef.sig.ret).unwrap();
@@ -61,12 +67,22 @@ fn print_function_in(module: &Module, func: &Function) -> String {
6167
     let mut out = String::new();
6268
     // Print function attributes.
6369
     let mut attrs = Vec::new();
64
-    if func.is_pure { attrs.push("pure"); }
65
-    if func.is_elemental { attrs.push("elemental"); }
66
-    let attr_str = if attrs.is_empty() { String::new() } else { format!(" [{}]", attrs.join(", ")) };
70
+    if func.is_pure {
71
+        attrs.push("pure");
72
+    }
73
+    if func.is_elemental {
74
+        attrs.push("elemental");
75
+    }
76
+    let attr_str = if attrs.is_empty() {
77
+        String::new()
78
+    } else {
79
+        format!(" [{}]", attrs.join(", "))
80
+    };
6781
     write!(out, "  func @{}{}(", func.name, attr_str).unwrap();
6882
     for (i, p) in func.params.iter().enumerate() {
69
-        if i > 0 { write!(out, ", ").unwrap(); }
83
+        if i > 0 {
84
+            write!(out, ", ").unwrap();
85
+        }
7086
         write!(out, "%{}: {}", p.id.0, p.ty).unwrap();
7187
     }
7288
     writeln!(out, ") -> {} {{", func.return_type).unwrap();
@@ -93,11 +109,17 @@ fn print_block_with_module(block: &BasicBlock, func: &Function, module: &Module)
93109
     print_block_with_module_opt(block, func, Some(module))
94110
 }
95111
 
96
-fn print_block_with_module_opt(block: &BasicBlock, func: &Function, module: Option<&Module>) -> String {
112
+fn print_block_with_module_opt(
113
+    block: &BasicBlock,
114
+    func: &Function,
115
+    module: Option<&Module>,
116
+) -> String {
97117
     let mut out = String::new();
98118
     write!(out, "    {}(", block.name).unwrap();
99119
     for (i, bp) in block.params.iter().enumerate() {
100
-        if i > 0 { write!(out, ", ").unwrap(); }
120
+        if i > 0 {
121
+            write!(out, ", ").unwrap();
122
+        }
101123
         write!(out, "%{}: {}", bp.id.0, bp.ty).unwrap();
102124
     }
103125
     writeln!(out, "):").unwrap();
@@ -118,7 +140,9 @@ pub fn print_block(block: &BasicBlock) -> String {
118140
     let mut out = String::new();
119141
     write!(out, "    {}(", block.name).unwrap();
120142
     for (i, bp) in block.params.iter().enumerate() {
121
-        if i > 0 { write!(out, ", ").unwrap(); }
143
+        if i > 0 {
144
+            write!(out, ", ").unwrap();
145
+        }
122146
         write!(out, "%{}: {}", bp.id.0, bp.ty).unwrap();
123147
     }
124148
     writeln!(out, "):").unwrap();
@@ -143,12 +167,22 @@ fn print_function_with_module_opt(module: Option<&Module>, func: &Function) -> S
143167
     let mut out = String::new();
144168
     // Print function attributes.
145169
     let mut attrs = Vec::new();
146
-    if func.is_pure { attrs.push("pure"); }
147
-    if func.is_elemental { attrs.push("elemental"); }
148
-    let attr_str = if attrs.is_empty() { String::new() } else { format!(" [{}]", attrs.join(", ")) };
170
+    if func.is_pure {
171
+        attrs.push("pure");
172
+    }
173
+    if func.is_elemental {
174
+        attrs.push("elemental");
175
+    }
176
+    let attr_str = if attrs.is_empty() {
177
+        String::new()
178
+    } else {
179
+        format!(" [{}]", attrs.join(", "))
180
+    };
149181
     write!(out, "  func @{}{}(", func.name, attr_str).unwrap();
150182
     for (i, p) in func.params.iter().enumerate() {
151
-        if i > 0 { write!(out, ", ").unwrap(); }
183
+        if i > 0 {
184
+            write!(out, ", ").unwrap();
185
+        }
152186
         write!(out, "%{}: {}", p.id.0, p.ty).unwrap();
153187
     }
154188
     writeln!(out, ") -> {} {{", func.return_type).unwrap();
@@ -210,7 +244,12 @@ fn print_inst_with_module_opt(inst: &Inst, module: Option<&Module>) -> String {
210244
         InstKind::FloatToInt(v, w) => format!("float_to_int %{} : {}", v.0, w),
211245
         InstKind::FloatExtend(v, w) => format!("float_extend %{} : {}", v.0, w),
212246
         InstKind::FloatTrunc(v, w) => format!("float_trunc %{} : {}", v.0, w),
213
-        InstKind::IntExtend(v, w, s) => format!("int_extend %{} : {} {}", v.0, w, if *s { "signed" } else { "unsigned" }),
247
+        InstKind::IntExtend(v, w, s) => format!(
248
+            "int_extend %{} : {} {}",
249
+            v.0,
250
+            w,
251
+            if *s { "signed" } else { "unsigned" }
252
+        ),
214253
         InstKind::IntTrunc(v, w) => format!("int_trunc %{} : {}", v.0, w),
215254
         InstKind::PtrToInt(v) => format!("ptr_to_int %{}", v.0),
216255
         InstKind::IntToPtr(v, ty) => format!("int_to_ptr %{} : {}", v.0, ty),
@@ -238,11 +277,17 @@ fn print_inst_with_module_opt(inst: &Inst, module: Option<&Module>) -> String {
238277
         }
239278
         InstKind::RuntimeCall(rf, args) => {
240279
             let args_str: Vec<String> = args.iter().map(|a| format!("%{}", a.0)).collect();
241
-            format!("rt_call @{}({})", runtime_func_name(rf), args_str.join(", "))
280
+            format!(
281
+                "rt_call @{}({})",
282
+                runtime_func_name(rf),
283
+                args_str.join(", ")
284
+            )
242285
         }
243286
 
244287
         InstKind::ExtractField(agg, idx) => format!("extract_field %{}, {}", agg.0, idx),
245
-        InstKind::InsertField(agg, idx, val) => format!("insert_field %{}, {}, %{}", agg.0, idx, val.0),
288
+        InstKind::InsertField(agg, idx, val) => {
289
+            format!("insert_field %{}, {}, %{}", agg.0, idx, val.0)
290
+        }
246291
     };
247292
 
248293
     if inst.ty == super::types::IrType::Void {
@@ -266,17 +311,39 @@ pub fn print_terminator_with_names(term: &Terminator, func: &Function) -> String
266311
                 format!("br {}({})", bname(dest), args_str.join(", "))
267312
             }
268313
         }
269
-        Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args } => {
314
+        Terminator::CondBranch {
315
+            cond,
316
+            true_dest,
317
+            true_args,
318
+            false_dest,
319
+            false_args,
320
+        } => {
270321
             let ta: Vec<String> = true_args.iter().map(|a| format!("%{}", a.0)).collect();
271322
             let fa: Vec<String> = false_args.iter().map(|a| format!("%{}", a.0)).collect();
272
-            format!("cond_br %{}, {}({}), {}({})",
273
-                cond.0, bname(true_dest), ta.join(", "), bname(false_dest), fa.join(", "))
323
+            format!(
324
+                "cond_br %{}, {}({}), {}({})",
325
+                cond.0,
326
+                bname(true_dest),
327
+                ta.join(", "),
328
+                bname(false_dest),
329
+                fa.join(", ")
330
+            )
274331
         }
275
-        Terminator::Switch { selector, cases, default } => {
276
-            let cases_str: Vec<String> = cases.iter()
332
+        Terminator::Switch {
333
+            selector,
334
+            cases,
335
+            default,
336
+        } => {
337
+            let cases_str: Vec<String> = cases
338
+                .iter()
277339
                 .map(|(v, b)| format!("{} -> {}", v, bname(b)))
278340
                 .collect();
279
-            format!("switch %{}, [{}], default {}", selector.0, cases_str.join(", "), bname(default))
341
+            format!(
342
+                "switch %{}, [{}], default {}",
343
+                selector.0,
344
+                cases_str.join(", "),
345
+                bname(default)
346
+            )
280347
         }
281348
         Terminator::Unreachable => "unreachable".into(),
282349
     }
@@ -295,17 +362,39 @@ pub fn print_terminator(term: &Terminator) -> String {
295362
                 format!("br bb{}({})", dest.0, args_str.join(", "))
296363
             }
297364
         }
298
-        Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args } => {
365
+        Terminator::CondBranch {
366
+            cond,
367
+            true_dest,
368
+            true_args,
369
+            false_dest,
370
+            false_args,
371
+        } => {
299372
             let ta: Vec<String> = true_args.iter().map(|a| format!("%{}", a.0)).collect();
300373
             let fa: Vec<String> = false_args.iter().map(|a| format!("%{}", a.0)).collect();
301
-            format!("cond_br %{}, bb{}({}), bb{}({})",
302
-                cond.0, true_dest.0, ta.join(", "), false_dest.0, fa.join(", "))
374
+            format!(
375
+                "cond_br %{}, bb{}({}), bb{}({})",
376
+                cond.0,
377
+                true_dest.0,
378
+                ta.join(", "),
379
+                false_dest.0,
380
+                fa.join(", ")
381
+            )
303382
         }
304
-        Terminator::Switch { selector, cases, default } => {
305
-            let cases_str: Vec<String> = cases.iter()
383
+        Terminator::Switch {
384
+            selector,
385
+            cases,
386
+            default,
387
+        } => {
388
+            let cases_str: Vec<String> = cases
389
+                .iter()
306390
                 .map(|(v, b)| format!("{} -> bb{}", v, b.0))
307391
                 .collect();
308
-            format!("switch %{}, [{}], default bb{}", selector.0, cases_str.join(", "), default.0)
392
+            format!(
393
+                "switch %{}, [{}], default bb{}",
394
+                selector.0,
395
+                cases_str.join(", "),
396
+                default.0
397
+            )
309398
         }
310399
         Terminator::Unreachable => "unreachable".into(),
311400
     }
@@ -342,9 +431,9 @@ fn runtime_func_name(rf: &RuntimeFunc) -> &'static str {
342431
 
343432
 #[cfg(test)]
344433
 mod tests {
345
-    use super::*;
346
-    use super::super::types::*;
347434
     use super::super::builder::FuncBuilder;
435
+    use super::super::types::*;
436
+    use super::*;
348437
 
349438
     #[test]
350439
     fn print_simple_function() {
@@ -422,7 +511,11 @@ mod tests {
422511
         let output = print_function(&func);
423512
         assert!(output.contains("header_1(%"));
424513
         assert!(output.contains(": i32)"));
425
-        assert!(output.contains("br header_1("), "expected 'br header_1(' in:\n{}", output);
514
+        assert!(
515
+            output.contains("br header_1("),
516
+            "expected 'br header_1(' in:\n{}",
517
+            output
518
+        );
426519
     }
427520
 
428521
     #[test]
@@ -443,13 +536,25 @@ mod tests {
443536
         {
444537
             let mut b = FuncBuilder::new(&mut caller);
445538
             let arg = b.const_i32(7);
446
-            let _ = b.call(FuncRef::Internal(callee_idx), vec![arg], IrType::Int(IntWidth::I32));
539
+            let _ = b.call(
540
+                FuncRef::Internal(callee_idx),
541
+                vec![arg],
542
+                IrType::Int(IntWidth::I32),
543
+            );
447544
             b.ret_void();
448545
         }
449546
         module.add_function(caller);
450547
 
451548
         let output = print_module(&module);
452
-        assert!(output.contains("call @callee("), "expected named internal call in:\n{}", output);
453
-        assert!(!output.contains("@func_0"), "unexpected fallback name in:\n{}", output);
549
+        assert!(
550
+            output.contains("call @callee("),
551
+            "expected named internal call in:\n{}",
552
+            output
553
+        );
554
+        assert!(
555
+            !output.contains("@func_0"),
556
+            "unexpected fallback name in:\n{}",
557
+            output
558
+        );
454559
     }
455560
 }
src/ir/types.rsmodified
62 lines changed — click to load
@@ -55,7 +55,10 @@ pub enum FloatWidth {
5555
 
5656
 impl FloatWidth {
5757
     pub fn bits(self) -> u32 {
58
-        match self { Self::F32 => 32, Self::F64 => 64 }
58
+        match self {
59
+            Self::F32 => 32,
60
+            Self::F64 => 64,
61
+        }
5962
     }
6063
 
6164
     pub fn bytes(self) -> u32 {
@@ -90,7 +93,9 @@ impl IrType {
9093
             Self::Float(w) => w.bytes() as u64,
9194
             Self::Ptr(_) => 8, // 64-bit pointers
9295
             Self::Array(elem, count) => elem.size_bytes() * count,
93
-            Self::Struct(_) => panic!("Struct size requires struct_defs; use Module::struct_size()"),
96
+            Self::Struct(_) => {
97
+                panic!("Struct size requires struct_defs; use Module::struct_size()")
98
+            }
9499
             Self::FuncPtr(_) => 8,
95100
         }
96101
     }
@@ -102,17 +107,27 @@ impl IrType {
102107
 
103108
     /// Extract the IntWidth if this is an integer type.
104109
     pub fn int_width(&self) -> Option<IntWidth> {
105
-        if let Self::Int(w) = self { Some(*w) } else { None }
110
+        if let Self::Int(w) = self {
111
+            Some(*w)
112
+        } else {
113
+            None
114
+        }
106115
     }
107116
 
108117
     /// Is this an integer type?
109
-    pub fn is_int(&self) -> bool { matches!(self, Self::Int(_)) }
118
+    pub fn is_int(&self) -> bool {
119
+        matches!(self, Self::Int(_))
120
+    }
110121
 
111122
     /// Is this a float type?
112
-    pub fn is_float(&self) -> bool { matches!(self, Self::Float(_)) }
123
+    pub fn is_float(&self) -> bool {
124
+        matches!(self, Self::Float(_))
125
+    }
113126
 
114127
     /// Is this a pointer type?
115
-    pub fn is_ptr(&self) -> bool { matches!(self, Self::Ptr(_)) }
128
+    pub fn is_ptr(&self) -> bool {
129
+        matches!(self, Self::Ptr(_))
130
+    }
116131
 
117132
     /// Fortran integer(1) → i8, integer(2) → i16, integer(4) → i32,
118133
     /// integer(8) → i64, integer(16) → i128.
@@ -149,7 +164,9 @@ impl std::fmt::Display for IrType {
149164
             Self::FuncPtr(sig) => {
150165
                 write!(f, "fn(")?;
151166
                 for (i, p) in sig.params.iter().enumerate() {
152
-                    if i > 0 { write!(f, ", ")?; }
167
+                    if i > 0 {
168
+                        write!(f, ", ")?;
169
+                    }
153170
                     write!(f, "{}", p)?;
154171
                 }
155172
                 write!(f, ") -> {}", sig.ret)
src/ir/verify.rsmodified
347 lines changed — click to load
@@ -4,10 +4,10 @@
44
 //! Checks: SSA dominance, type consistency, block structure,
55
 //! terminator completeness, block param/branch arg matching.
66
 
7
-use std::collections::{HashMap, HashSet};
87
 use super::inst::*;
9
-use super::types::{IrType, IntWidth};
10
-use super::walk::{inst_uses, terminator_uses, terminator_targets, compute_dominators};
8
+use super::types::{IntWidth, IrType};
9
+use super::walk::{compute_dominators, inst_uses, terminator_targets, terminator_uses};
10
+use std::collections::{HashMap, HashSet};
1111
 
1212
 /// Verification error.
1313
 #[derive(Debug, Clone)]
@@ -59,7 +59,9 @@ pub fn verify_function(func: &Function) -> Vec<VerifyError> {
5959
         });
6060
     }
6161
     for block in &func.blocks {
62
-        let Some(term) = &block.terminator else { continue; };
62
+        let Some(term) = &block.terminator else {
63
+            continue;
64
+        };
6365
         if terminator_targets(term).contains(&func.entry) {
6466
             errors.push(VerifyError {
6567
                 msg: format!(
@@ -78,8 +80,10 @@ pub fn verify_function(func: &Function) -> Vec<VerifyError> {
7880
             for used in inst_uses(&inst.kind) {
7981
                 if !defined.contains(&used) {
8082
                     errors.push(VerifyError {
81
-                        msg: format!("value %{} used in block '{}' but not defined",
82
-                            used.0, block.name),
83
+                        msg: format!(
84
+                            "value %{} used in block '{}' but not defined",
85
+                            used.0, block.name
86
+                        ),
8387
                     });
8488
                 }
8589
             }
@@ -88,8 +92,10 @@ pub fn verify_function(func: &Function) -> Vec<VerifyError> {
8892
             for used in terminator_uses(term) {
8993
                 if !defined.contains(&used) {
9094
                     errors.push(VerifyError {
91
-                        msg: format!("value %{} used in terminator of block '{}' but not defined",
92
-                            used.0, block.name),
95
+                        msg: format!(
96
+                            "value %{} used in terminator of block '{}' but not defined",
97
+                            used.0, block.name
98
+                        ),
9399
                     });
94100
                 }
95101
             }
@@ -164,8 +170,10 @@ pub fn verify_function(func: &Function) -> Vec<VerifyError> {
164170
             for target in terminator_targets(term) {
165171
                 if !block_ids.contains(&target) {
166172
                     errors.push(VerifyError {
167
-                        msg: format!("block '{}' branches to undefined block {}",
168
-                            block.name, target.0),
173
+                        msg: format!(
174
+                            "block '{}' branches to undefined block {}",
175
+                            block.name, target.0
176
+                        ),
169177
                     });
170178
                 }
171179
             }
@@ -276,14 +284,22 @@ fn collect_defined_values(func: &Function) -> HashSet<ValueId> {
276284
 }
277285
 
278286
 /// Check that branch arguments match block parameters in count and type.
279
-fn check_branch_args(func: &Function, term: &Terminator, from_block: &str, errors: &mut Vec<VerifyError>) {
287
+fn check_branch_args(
288
+    func: &Function,
289
+    term: &Terminator,
290
+    from_block: &str,
291
+    errors: &mut Vec<VerifyError>,
292
+) {
280293
     let mut check = |dest: BlockId, args: &[ValueId]| {
281294
         let target = func.block(dest);
282295
         if target.params.len() != args.len() {
283296
             errors.push(VerifyError {
284297
                 msg: format!(
285298
                     "branch from '{}' to '{}': expected {} args, got {}",
286
-                    from_block, target.name, target.params.len(), args.len()
299
+                    from_block,
300
+                    target.name,
301
+                    target.params.len(),
302
+                    args.len()
287303
                 ),
288304
             });
289305
         } else {
@@ -305,7 +321,13 @@ fn check_branch_args(func: &Function, term: &Terminator, from_block: &str, error
305321
 
306322
     match term {
307323
         Terminator::Branch(dest, args) => check(*dest, args),
308
-        Terminator::CondBranch { true_dest, true_args, false_dest, false_args, .. } => {
324
+        Terminator::CondBranch {
325
+            true_dest,
326
+            true_args,
327
+            false_dest,
328
+            false_args,
329
+            ..
330
+        } => {
309331
             check(*true_dest, true_args);
310332
             check(*false_dest, false_args);
311333
         }
@@ -314,7 +336,10 @@ fn check_branch_args(func: &Function, term: &Terminator, from_block: &str, error
314336
             let default_block = func.block(*default);
315337
             if !default_block.params.is_empty() {
316338
                 errors.push(VerifyError {
317
-                    msg: format!("switch default target '{}' has block parameters", default_block.name),
339
+                    msg: format!(
340
+                        "switch default target '{}' has block parameters",
341
+                        default_block.name
342
+                    ),
318343
                 });
319344
             }
320345
             for (_, dest) in cases {
@@ -333,9 +358,11 @@ fn check_branch_args(func: &Function, term: &Terminator, from_block: &str, error
333358
 /// Check type consistency for instructions.
334359
 fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyError>) {
335360
     match &inst.kind {
336
-        InstKind::IAdd(a, b) | InstKind::ISub(a, b) |
337
-        InstKind::IMul(a, b) | InstKind::IDiv(a, b) |
338
-        InstKind::IMod(a, b) => {
361
+        InstKind::IAdd(a, b)
362
+        | InstKind::ISub(a, b)
363
+        | InstKind::IMul(a, b)
364
+        | InstKind::IDiv(a, b)
365
+        | InstKind::IMod(a, b) => {
339366
             let ta = func.value_type(*a);
340367
             let tb = func.value_type(*b);
341368
             // Report missing types so the upstream cache-miss (already
@@ -354,12 +381,18 @@ fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyE
354381
             if let (Some(ta), Some(tb)) = (&ta, &tb) {
355382
                 if !ta.is_int() {
356383
                     errors.push(VerifyError {
357
-                        msg: format!("integer op %{} has non-integer operand %{} : {}", inst.id.0, a.0, ta),
384
+                        msg: format!(
385
+                            "integer op %{} has non-integer operand %{} : {}",
386
+                            inst.id.0, a.0, ta
387
+                        ),
358388
                     });
359389
                 }
360390
                 if !tb.is_int() {
361391
                     errors.push(VerifyError {
362
-                        msg: format!("integer op %{} has non-integer operand %{} : {}", inst.id.0, b.0, tb),
392
+                        msg: format!(
393
+                            "integer op %{} has non-integer operand %{} : {}",
394
+                            inst.id.0, b.0, tb
395
+                        ),
363396
                     });
364397
                 }
365398
                 // Audit MAJOR-4: enforce exact width agreement.
@@ -380,20 +413,28 @@ fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyE
380413
                 }
381414
             }
382415
         }
383
-        InstKind::FAdd(a, b) | InstKind::FSub(a, b) |
384
-        InstKind::FMul(a, b) | InstKind::FDiv(a, b) |
385
-        InstKind::FPow(a, b) => {
416
+        InstKind::FAdd(a, b)
417
+        | InstKind::FSub(a, b)
418
+        | InstKind::FMul(a, b)
419
+        | InstKind::FDiv(a, b)
420
+        | InstKind::FPow(a, b) => {
386421
             let ta = func.value_type(*a);
387422
             let tb = func.value_type(*b);
388423
             if let (Some(ta), Some(tb)) = (&ta, &tb) {
389424
                 if !ta.is_float() {
390425
                     errors.push(VerifyError {
391
-                        msg: format!("float op %{} has non-float operand %{} : {}", inst.id.0, a.0, ta),
426
+                        msg: format!(
427
+                            "float op %{} has non-float operand %{} : {}",
428
+                            inst.id.0, a.0, ta
429
+                        ),
392430
                     });
393431
                 }
394432
                 if !tb.is_float() {
395433
                     errors.push(VerifyError {
396
-                        msg: format!("float op %{} has non-float operand %{} : {}", inst.id.0, b.0, tb),
434
+                        msg: format!(
435
+                            "float op %{} has non-float operand %{} : {}",
436
+                            inst.id.0, b.0, tb
437
+                        ),
397438
                     });
398439
                 }
399440
                 // Same width-agreement rule for floats. Mixing
@@ -423,9 +464,7 @@ fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyE
423464
             // A Store(i64_val, ptr<i32>) would silently truncate
424465
             // at codegen because isel picks the str width from
425466
             // the value's reg class, not the pointer's pointee.
426
-            if let (Some(IrType::Ptr(pointee)), Some(vty)) =
427
-                (&addr_ty, func.value_type(*val))
428
-            {
467
+            if let (Some(IrType::Ptr(pointee)), Some(vty)) = (&addr_ty, func.value_type(*val)) {
429468
                 let inner: &IrType = pointee.as_ref();
430469
                 // Byte-level GEPs into derived-type layouts use
431470
                 // `ptr<i8>` as a marker with arbitrary pointee on
@@ -457,8 +496,12 @@ fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyE
457496
 
458497
         // Bitwise binary ops: both operands must be integers of
459498
         // the same width. Audit Med-1.
460
-        InstKind::BitAnd(a, b) | InstKind::BitOr(a, b) | InstKind::BitXor(a, b)
461
-        | InstKind::Shl(a, b) | InstKind::LShr(a, b) | InstKind::AShr(a, b) => {
499
+        InstKind::BitAnd(a, b)
500
+        | InstKind::BitOr(a, b)
501
+        | InstKind::BitXor(a, b)
502
+        | InstKind::Shl(a, b)
503
+        | InstKind::LShr(a, b)
504
+        | InstKind::AShr(a, b) => {
462505
             let ta = func.value_type(*a);
463506
             let tb = func.value_type(*b);
464507
             if let (Some(ta), Some(tb)) = (&ta, &tb) {
@@ -503,9 +546,9 @@ fn check_type_consistency(func: &Function, inst: &Inst, errors: &mut Vec<VerifyE
503546
 
504547
 #[cfg(test)]
505548
 mod tests {
506
-    use super::*;
507
-    use super::super::types::*;
508549
     use super::super::builder::FuncBuilder;
550
+    use super::super::types::*;
551
+    use super::*;
509552
 
510553
     #[test]
511554
     fn valid_simple_function() {
@@ -551,7 +594,8 @@ mod tests {
551594
         let mut func = Function::new("test".into(), vec![], IrType::Void);
552595
         // Manually add a param to the entry block.
553596
         func.blocks[0].params.push(BlockParam {
554
-            id: ValueId(99), ty: IrType::Int(IntWidth::I32),
597
+            id: ValueId(99),
598
+            ty: IrType::Int(IntWidth::I32),
555599
         });
556600
         func.blocks[0].terminator = Some(Terminator::Return(None));
557601
         let errs = verify_function(&func);
@@ -568,7 +612,8 @@ mod tests {
568612
         let errs = verify_function(&func);
569613
         assert!(
570614
             errs.iter().any(|e| e.msg.contains("entry block")),
571
-            "expected entry-back-edge error, got: {:?}", errs,
615
+            "expected entry-back-edge error, got: {:?}",
616
+            errs,
572617
         );
573618
     }
574619
 
@@ -586,7 +631,9 @@ mod tests {
586631
             b.ret_void();
587632
         }
588633
         let errs = verify_function(&func);
589
-        assert!(errs.iter().any(|e| e.msg.contains("expected 1 args, got 0")));
634
+        assert!(errs
635
+            .iter()
636
+            .any(|e| e.msg.contains("expected 1 args, got 0")));
590637
     }
591638
 
592639
     #[test]
@@ -619,7 +666,8 @@ mod tests {
619666
         }
620667
         let errs = verify_function(&func);
621668
         assert!(
622
-            errs.iter().any(|e| e.msg.contains("doesn't match pointee type")),
669
+            errs.iter()
670
+                .any(|e| e.msg.contains("doesn't match pointee type")),
623671
             "expected pointee type mismatch error, got: {:?}",
624672
             errs,
625673
         );
@@ -734,7 +782,7 @@ mod tests {
734782
             let mut b = FuncBuilder::new(&mut func);
735783
             let val = b.const_i32(42);
736784
             let not_ptr = b.const_i32(0); // not a pointer
737
-            // Force a store to non-pointer.
785
+                                          // Force a store to non-pointer.
738786
             b.emit_bogus_store(val, not_ptr);
739787
             b.ret_void();
740788
         }
@@ -767,25 +815,39 @@ mod tests {
767815
             b.ret_void();
768816
         }
769817
         // Manually inject the value definition in block B with the ID we referenced.
770
-        use crate::lexer::{Span, Position};
771
-        let span = Span { file_id: 0, start: Position { line: 0, col: 0 }, end: Position { line: 0, col: 0 } };
772
-        func.blocks[2].insts.insert(0, Inst {
773
-            id: ValueId(100),
774
-            kind: InstKind::ConstInt(99, IntWidth::I32),
775
-            ty: IrType::Int(IntWidth::I32),
776
-            span,
777
-        });
818
+        use crate::lexer::{Position, Span};
819
+        let span = Span {
820
+            file_id: 0,
821
+            start: Position { line: 0, col: 0 },
822
+            end: Position { line: 0, col: 0 },
823
+        };
824
+        func.blocks[2].insts.insert(
825
+            0,
826
+            Inst {
827
+                id: ValueId(100),
828
+                kind: InstKind::ConstInt(99, IntWidth::I32),
829
+                ty: IrType::Int(IntWidth::I32),
830
+                span,
831
+            },
832
+        );
778833
         let errs = verify_function(&func);
779
-        assert!(errs.iter().any(|e| e.msg.contains("does not dominate")),
780
-            "expected dominance error, got: {:?}", errs);
834
+        assert!(
835
+            errs.iter().any(|e| e.msg.contains("does not dominate")),
836
+            "expected dominance error, got: {:?}",
837
+            errs
838
+        );
781839
     }
782840
 
783841
     #[test]
784842
     fn dominance_same_block_order_violation() {
785843
         // Use a value before it's defined in the same block.
786844
         let mut func = Function::new("test".into(), vec![], IrType::Void);
787
-        use crate::lexer::{Span, Position};
788
-        let span = Span { file_id: 0, start: Position { line: 0, col: 0 }, end: Position { line: 0, col: 0 } };
845
+        use crate::lexer::{Position, Span};
846
+        let span = Span {
847
+            file_id: 0,
848
+            start: Position { line: 0, col: 0 },
849
+            end: Position { line: 0, col: 0 },
850
+        };
789851
 
790852
         // Manually construct: %1 = iadd %0, %0 then %0 = const_int 42
791853
         // (use of %0 before its definition)
@@ -803,8 +865,12 @@ mod tests {
803865
         });
804866
         func.blocks[0].terminator = Some(Terminator::Return(None));
805867
         let errs = verify_function(&func);
806
-        assert!(errs.iter().any(|e| e.msg.contains("used before its definition")),
807
-            "expected same-block order error, got: {:?}", errs);
868
+        assert!(
869
+            errs.iter()
870
+                .any(|e| e.msg.contains("used before its definition")),
871
+            "expected same-block order error, got: {:?}",
872
+            errs
873
+        );
808874
     }
809875
 
810876
     #[test]
@@ -837,13 +903,23 @@ mod tests {
837903
     fn duplicate_value_id_errors() {
838904
         let mut func = Function::new("test".into(), vec![], IrType::Void);
839905
         // Manually push two instructions with the same ID.
840
-        use crate::lexer::{Span, Position};
841
-        let span = Span { file_id: 0, start: Position { line: 0, col: 0 }, end: Position { line: 0, col: 0 } };
906
+        use crate::lexer::{Position, Span};
907
+        let span = Span {
908
+            file_id: 0,
909
+            start: Position { line: 0, col: 0 },
910
+            end: Position { line: 0, col: 0 },
911
+        };
842912
         func.blocks[0].insts.push(Inst {
843
-            id: ValueId(0), kind: InstKind::ConstInt(1, IntWidth::I32), ty: IrType::Int(IntWidth::I32), span,
913
+            id: ValueId(0),
914
+            kind: InstKind::ConstInt(1, IntWidth::I32),
915
+            ty: IrType::Int(IntWidth::I32),
916
+            span,
844917
         });
845918
         func.blocks[0].insts.push(Inst {
846
-            id: ValueId(0), kind: InstKind::ConstInt(2, IntWidth::I32), ty: IrType::Int(IntWidth::I32), span,
919
+            id: ValueId(0),
920
+            kind: InstKind::ConstInt(2, IntWidth::I32),
921
+            ty: IrType::Int(IntWidth::I32),
922
+            span,
847923
         });
848924
         func.blocks[0].terminator = Some(Terminator::Return(None));
849925
         let errs = verify_function(&func);
src/ir/walk.rsmodified
616 lines changed — click to load
@@ -23,19 +23,26 @@ use std::collections::{HashMap, HashSet, VecDeque};
2323
 /// All `ValueId`s consumed as operands by an instruction.
2424
 pub fn inst_uses(kind: &InstKind) -> Vec<ValueId> {
2525
     match kind {
26
-        InstKind::ConstInt(..) | InstKind::ConstFloat(..) |
27
-        InstKind::ConstBool(..) | InstKind::ConstString(..) |
28
-        InstKind::Undef(..) | InstKind::Alloca(..) |
29
-        InstKind::GlobalAddr(..) => vec![],
30
-
31
-        InstKind::IAdd(a, b) | InstKind::ISub(a, b) |
32
-        InstKind::IMul(a, b) | InstKind::IDiv(a, b) |
33
-        InstKind::IMod(a, b) => vec![*a, *b],
26
+        InstKind::ConstInt(..)
27
+        | InstKind::ConstFloat(..)
28
+        | InstKind::ConstBool(..)
29
+        | InstKind::ConstString(..)
30
+        | InstKind::Undef(..)
31
+        | InstKind::Alloca(..)
32
+        | InstKind::GlobalAddr(..) => vec![],
33
+
34
+        InstKind::IAdd(a, b)
35
+        | InstKind::ISub(a, b)
36
+        | InstKind::IMul(a, b)
37
+        | InstKind::IDiv(a, b)
38
+        | InstKind::IMod(a, b) => vec![*a, *b],
3439
         InstKind::INeg(a) => vec![*a],
3540
 
36
-        InstKind::FAdd(a, b) | InstKind::FSub(a, b) |
37
-        InstKind::FMul(a, b) | InstKind::FDiv(a, b) |
38
-        InstKind::FPow(a, b) => vec![*a, *b],
41
+        InstKind::FAdd(a, b)
42
+        | InstKind::FSub(a, b)
43
+        | InstKind::FMul(a, b)
44
+        | InstKind::FDiv(a, b)
45
+        | InstKind::FPow(a, b) => vec![*a, *b],
3946
         InstKind::FNeg(a) | InstKind::FAbs(a) | InstKind::FSqrt(a) => vec![*a],
4047
 
4148
         InstKind::ICmp(_, a, b) | InstKind::FCmp(_, a, b) => vec![*a, *b],
@@ -45,16 +52,25 @@ pub fn inst_uses(kind: &InstKind) -> Vec<ValueId> {
4552
 
4653
         InstKind::Select(c, t, f) => vec![*c, *t, *f],
4754
 
48
-        InstKind::BitAnd(a, b) | InstKind::BitOr(a, b) |
49
-        InstKind::BitXor(a, b) | InstKind::Shl(a, b) |
50
-        InstKind::LShr(a, b) | InstKind::AShr(a, b) => vec![*a, *b],
51
-        InstKind::BitNot(a) | InstKind::CountLeadingZeros(a) |
52
-        InstKind::CountTrailingZeros(a) | InstKind::PopCount(a) => vec![*a],
53
-
54
-        InstKind::IntToFloat(v, _) | InstKind::FloatToInt(v, _) |
55
-        InstKind::FloatExtend(v, _) | InstKind::FloatTrunc(v, _) |
56
-        InstKind::IntExtend(v, _, _) | InstKind::IntTrunc(v, _) |
57
-        InstKind::PtrToInt(v) | InstKind::IntToPtr(v, _) => vec![*v],
55
+        InstKind::BitAnd(a, b)
56
+        | InstKind::BitOr(a, b)
57
+        | InstKind::BitXor(a, b)
58
+        | InstKind::Shl(a, b)
59
+        | InstKind::LShr(a, b)
60
+        | InstKind::AShr(a, b) => vec![*a, *b],
61
+        InstKind::BitNot(a)
62
+        | InstKind::CountLeadingZeros(a)
63
+        | InstKind::CountTrailingZeros(a)
64
+        | InstKind::PopCount(a) => vec![*a],
65
+
66
+        InstKind::IntToFloat(v, _)
67
+        | InstKind::FloatToInt(v, _)
68
+        | InstKind::FloatExtend(v, _)
69
+        | InstKind::FloatTrunc(v, _)
70
+        | InstKind::IntExtend(v, _, _)
71
+        | InstKind::IntTrunc(v, _)
72
+        | InstKind::PtrToInt(v)
73
+        | InstKind::IntToPtr(v, _) => vec![*v],
5874
 
5975
         InstKind::Load(a) => vec![*a],
6076
         InstKind::Store(v, a) => vec![*v, *a],
@@ -82,7 +98,12 @@ pub fn terminator_uses(term: &Terminator) -> Vec<ValueId> {
8298
         Terminator::Return(None) | Terminator::Unreachable => vec![],
8399
         Terminator::Return(Some(v)) => vec![*v],
84100
         Terminator::Branch(_, args) => args.clone(),
85
-        Terminator::CondBranch { cond, true_args, false_args, .. } => {
101
+        Terminator::CondBranch {
102
+            cond,
103
+            true_args,
104
+            false_args,
105
+            ..
106
+        } => {
86107
             let mut uses = vec![*cond];
87108
             uses.extend(true_args);
88109
             uses.extend(false_args);
@@ -97,7 +118,11 @@ pub fn terminator_targets(term: &Terminator) -> Vec<BlockId> {
97118
     match term {
98119
         Terminator::Return(_) | Terminator::Unreachable => vec![],
99120
         Terminator::Branch(d, _) => vec![*d],
100
-        Terminator::CondBranch { true_dest, false_dest, .. } => vec![*true_dest, *false_dest],
121
+        Terminator::CondBranch {
122
+            true_dest,
123
+            false_dest,
124
+            ..
125
+        } => vec![*true_dest, *false_dest],
101126
         Terminator::Switch { cases, default, .. } => {
102127
             let mut t: Vec<BlockId> = cases.iter().map(|(_, b)| *b).collect();
103128
             t.push(*default);
@@ -113,72 +138,129 @@ pub fn terminator_targets(term: &Terminator) -> Vec<BlockId> {
113138
 /// Apply a closure to every operand slot of an instruction in place.
114139
 pub fn for_each_operand_mut(kind: &mut InstKind, mut r: impl FnMut(&mut ValueId)) {
115140
     match kind {
116
-        InstKind::ConstInt(..) | InstKind::ConstFloat(..) |
117
-        InstKind::ConstBool(..) | InstKind::ConstString(..) |
118
-        InstKind::Undef(..) | InstKind::Alloca(..) |
119
-        InstKind::GlobalAddr(..) => {}
120
-
121
-        InstKind::IAdd(a, b) | InstKind::ISub(a, b) |
122
-        InstKind::IMul(a, b) | InstKind::IDiv(a, b) |
123
-        InstKind::IMod(a, b) => { r(a); r(b); }
141
+        InstKind::ConstInt(..)
142
+        | InstKind::ConstFloat(..)
143
+        | InstKind::ConstBool(..)
144
+        | InstKind::ConstString(..)
145
+        | InstKind::Undef(..)
146
+        | InstKind::Alloca(..)
147
+        | InstKind::GlobalAddr(..) => {}
148
+
149
+        InstKind::IAdd(a, b)
150
+        | InstKind::ISub(a, b)
151
+        | InstKind::IMul(a, b)
152
+        | InstKind::IDiv(a, b)
153
+        | InstKind::IMod(a, b) => {
154
+            r(a);
155
+            r(b);
156
+        }
124157
         InstKind::INeg(a) => r(a),
125158
 
126
-        InstKind::FAdd(a, b) | InstKind::FSub(a, b) |
127
-        InstKind::FMul(a, b) | InstKind::FDiv(a, b) |
128
-        InstKind::FPow(a, b) => { r(a); r(b); }
159
+        InstKind::FAdd(a, b)
160
+        | InstKind::FSub(a, b)
161
+        | InstKind::FMul(a, b)
162
+        | InstKind::FDiv(a, b)
163
+        | InstKind::FPow(a, b) => {
164
+            r(a);
165
+            r(b);
166
+        }
129167
         InstKind::FNeg(a) | InstKind::FAbs(a) | InstKind::FSqrt(a) => r(a),
130168
 
131
-        InstKind::ICmp(_, a, b) | InstKind::FCmp(_, a, b) => { r(a); r(b); }
169
+        InstKind::ICmp(_, a, b) | InstKind::FCmp(_, a, b) => {
170
+            r(a);
171
+            r(b);
172
+        }
132173
 
133
-        InstKind::And(a, b) | InstKind::Or(a, b) => { r(a); r(b); }
174
+        InstKind::And(a, b) | InstKind::Or(a, b) => {
175
+            r(a);
176
+            r(b);
177
+        }
134178
         InstKind::Not(a) => r(a),
135179
 
136
-        InstKind::Select(c, t, f) => { r(c); r(t); r(f); }
137
-
138
-        InstKind::BitAnd(a, b) | InstKind::BitOr(a, b) |
139
-        InstKind::BitXor(a, b) | InstKind::Shl(a, b) |
140
-        InstKind::LShr(a, b) | InstKind::AShr(a, b) => { r(a); r(b); }
141
-        InstKind::BitNot(a) | InstKind::CountLeadingZeros(a) |
142
-        InstKind::CountTrailingZeros(a) | InstKind::PopCount(a) => r(a),
180
+        InstKind::Select(c, t, f) => {
181
+            r(c);
182
+            r(t);
183
+            r(f);
184
+        }
143185
 
144
-        InstKind::IntToFloat(v, _) | InstKind::FloatToInt(v, _) |
145
-        InstKind::FloatExtend(v, _) | InstKind::FloatTrunc(v, _) |
146
-        InstKind::IntExtend(v, _, _) | InstKind::IntTrunc(v, _) |
147
-        InstKind::PtrToInt(v) | InstKind::IntToPtr(v, _) => r(v),
186
+        InstKind::BitAnd(a, b)
187
+        | InstKind::BitOr(a, b)
188
+        | InstKind::BitXor(a, b)
189
+        | InstKind::Shl(a, b)
190
+        | InstKind::LShr(a, b)
191
+        | InstKind::AShr(a, b) => {
192
+            r(a);
193
+            r(b);
194
+        }
195
+        InstKind::BitNot(a)
196
+        | InstKind::CountLeadingZeros(a)
197
+        | InstKind::CountTrailingZeros(a)
198
+        | InstKind::PopCount(a) => r(a),
199
+
200
+        InstKind::IntToFloat(v, _)
201
+        | InstKind::FloatToInt(v, _)
202
+        | InstKind::FloatExtend(v, _)
203
+        | InstKind::FloatTrunc(v, _)
204
+        | InstKind::IntExtend(v, _, _)
205
+        | InstKind::IntTrunc(v, _)
206
+        | InstKind::PtrToInt(v)
207
+        | InstKind::IntToPtr(v, _) => r(v),
148208
 
149209
         InstKind::Load(a) => r(a),
150
-        InstKind::Store(v, a) => { r(v); r(a); }
210
+        InstKind::Store(v, a) => {
211
+            r(v);
212
+            r(a);
213
+        }
151214
         InstKind::GetElementPtr(base, idxs) => {
152215
             r(base);
153
-            for i in idxs { r(i); }
216
+            for i in idxs {
217
+                r(i);
218
+            }
154219
         }
155220
 
156221
         InstKind::Call(FuncRef::Indirect(target), args) => {
157222
             r(target);
158
-            for a in args { r(a); }
223
+            for a in args {
224
+                r(a);
225
+            }
159226
         }
160227
         InstKind::Call(_, args) | InstKind::RuntimeCall(_, args) => {
161
-            for a in args { r(a); }
228
+            for a in args {
229
+                r(a);
230
+            }
162231
         }
163232
 
164233
         InstKind::ExtractField(agg, _) => r(agg),
165
-        InstKind::InsertField(agg, _, val) => { r(agg); r(val); }
234
+        InstKind::InsertField(agg, _, val) => {
235
+            r(agg);
236
+            r(val);
237
+        }
166238
     }
167239
 }
168240
 
169241
 /// Apply a closure to every operand slot of a terminator in place.
170
-pub fn for_each_terminator_operand_mut(
171
-    term: &mut Terminator,
172
-    mut r: impl FnMut(&mut ValueId),
173
-) {
242
+pub fn for_each_terminator_operand_mut(term: &mut Terminator, mut r: impl FnMut(&mut ValueId)) {
174243
     match term {
175244
         Terminator::Return(None) | Terminator::Unreachable => {}
176245
         Terminator::Return(Some(v)) => r(v),
177
-        Terminator::Branch(_, args) => for a in args { r(a); },
178
-        Terminator::CondBranch { cond, true_args, false_args, .. } => {
246
+        Terminator::Branch(_, args) => {
247
+            for a in args {
248
+                r(a);
249
+            }
250
+        }
251
+        Terminator::CondBranch {
252
+            cond,
253
+            true_args,
254
+            false_args,
255
+            ..
256
+        } => {
179257
             r(cond);
180
-            for a in true_args { r(a); }
181
-            for a in false_args { r(a); }
258
+            for a in true_args {
259
+                r(a);
260
+            }
261
+            for a in false_args {
262
+                r(a);
263
+            }
182264
         }
183265
         Terminator::Switch { selector, .. } => r(selector),
184266
     }
@@ -188,7 +270,11 @@ pub fn for_each_terminator_operand_mut(
188270
 /// Definitions are unaffected — only operand slots in instructions and
189271
 /// terminators are rewritten.
190272
 pub fn substitute_uses(func: &mut Function, old: ValueId, new: ValueId) {
191
-    let r = |v: &mut ValueId| if *v == old { *v = new; };
273
+    let r = |v: &mut ValueId| {
274
+        if *v == old {
275
+            *v = new;
276
+        }
277
+    };
192278
     for block in &mut func.blocks {
193279
         for inst in &mut block.insts {
194280
             for_each_operand_mut(&mut inst.kind, r);
@@ -267,7 +353,9 @@ pub fn compute_dominators(func: &Function) -> HashMap<BlockId, HashSet<BlockId>>
267353
     // update them — they participate in no meaningful dominance
268354
     // relationship.
269355
     for block in &func.blocks {
270
-        if block.id == func.entry { continue; }
356
+        if block.id == func.entry {
357
+            continue;
358
+        }
271359
         if reachable.contains(&block.id) {
272360
             doms.insert(block.id, reachable.clone());
273361
         } else {
@@ -280,15 +368,22 @@ pub fn compute_dominators(func: &Function) -> HashMap<BlockId, HashSet<BlockId>>
280368
     while changed {
281369
         changed = false;
282370
         for block in &func.blocks {
283
-            if block.id == func.entry { continue; }
284
-            if !reachable.contains(&block.id) { continue; }
371
+            if block.id == func.entry {
372
+                continue;
373
+            }
374
+            if !reachable.contains(&block.id) {
375
+                continue;
376
+            }
285377
             let plist = preds.get(&block.id).cloned().unwrap_or_default();
286378
             // Reachable-only predecessors — an edge from an
287379
             // unreachable block doesn't contribute to dominance.
288
-            let reachable_preds: Vec<BlockId> = plist.into_iter()
380
+            let reachable_preds: Vec<BlockId> = plist
381
+                .into_iter()
289382
                 .filter(|p| reachable.contains(p))
290383
                 .collect();
291
-            if reachable_preds.is_empty() { continue; }
384
+            if reachable_preds.is_empty() {
385
+                continue;
386
+            }
292387
             let mut new_dom = reachable.clone();
293388
             for p in &reachable_preds {
294389
                 if let Some(pd) = doms.get(p) {
@@ -381,21 +476,24 @@ pub fn find_natural_loops(func: &Function) -> Vec<NaturalLoop> {
381476
         // everything reachable from the entry, which both inflates
382477
         // the body and makes `find_preheader` see no out-of-loop
383478
         // predecessor for the header.
384
-        let mut stack: Vec<BlockId> = latches.iter()
385
-            .filter(|&&l| l != header)
386
-            .copied()
387
-            .collect();
479
+        let mut stack: Vec<BlockId> = latches.iter().filter(|&&l| l != header).copied().collect();
388480
         while let Some(b) = stack.pop() {
389481
             if let Some(plist) = preds.get(&b) {
390482
                 for &p in plist {
391
-                    if p == header { continue; }
483
+                    if p == header {
484
+                        continue;
485
+                    }
392486
                     if body.insert(p) {
393487
                         stack.push(p);
394488
                     }
395489
                 }
396490
             }
397491
         }
398
-        loops.push(NaturalLoop { header, body, latches });
492
+        loops.push(NaturalLoop {
493
+            header,
494
+            body,
495
+            latches,
496
+        });
399497
     }
400498
     loops
401499
 }
@@ -414,7 +512,9 @@ pub fn prune_unreachable(func: &mut Function) -> bool {
414512
     queue.push_back(func.entry);
415513
     reachable.insert(func.entry);
416514
     while let Some(bid) = queue.pop_front() {
417
-        let Some(block) = func.try_block(bid) else { continue };
515
+        let Some(block) = func.try_block(bid) else {
516
+            continue;
517
+        };
418518
         if let Some(term) = &block.terminator {
419519
             for tgt in terminator_targets(term) {
420520
                 if reachable.insert(tgt) {
@@ -458,28 +558,31 @@ pub fn compute_immediate_dominators(func: &Function) -> HashMap<BlockId, BlockId
458558
     let mut idoms: HashMap<BlockId, BlockId> = HashMap::new();
459559
 
460560
     for block in &func.blocks {
461
-        if block.id == func.entry { continue; }
462
-        let Some(my_doms) = doms.get(&block.id) else { continue };
463
-        if my_doms.is_empty() { continue; } // unreachable
561
+        if block.id == func.entry {
562
+            continue;
563
+        }
564
+        let Some(my_doms) = doms.get(&block.id) else {
565
+            continue;
566
+        };
567
+        if my_doms.is_empty() {
568
+            continue;
569
+        } // unreachable
464570
 
465571
         // The immediate dominator is the dominator (other than
466572
         // self) that is dominated by every other dominator (other
467573
         // than self). Equivalently: the dominator that has the
468574
         // largest dominator set — all other dominators of `block`
469575
         // also dominate the idom.
470
-        let candidates: Vec<BlockId> = my_doms.iter()
471
-            .copied()
472
-            .filter(|&d| d != block.id)
473
-            .collect();
576
+        let candidates: Vec<BlockId> = my_doms.iter().copied().filter(|&d| d != block.id).collect();
474577
 
475578
         let idom = candidates.iter().copied().find(|&cand| {
476579
             // cand is idom iff no other candidate strictly
477580
             // dominates it (only cand itself and cand's own
478581
             // dominators do).
479582
             let cand_doms = doms.get(&cand).cloned().unwrap_or_default();
480
-            candidates.iter().all(|&other| {
481
-                other == cand || cand_doms.contains(&other)
482
-            })
583
+            candidates
584
+                .iter()
585
+                .all(|&other| other == cand || cand_doms.contains(&other))
483586
         });
484587
 
485588
         if let Some(idom) = idom {
@@ -496,9 +599,9 @@ pub fn compute_immediate_dominators(func: &Function) -> HashMap<BlockId, BlockId
496599
 /// `children[B]` is the set of blocks whose immediate dominator is
497600
 /// `B`. A dominator-tree traversal visits `B` then recurses into
498601
 /// `children[B]` in some order.
499
-pub fn dominator_tree_children(idoms: &HashMap<BlockId, BlockId>)
500
-    -> HashMap<BlockId, Vec<BlockId>>
501
-{
602
+pub fn dominator_tree_children(
603
+    idoms: &HashMap<BlockId, BlockId>,
604
+) -> HashMap<BlockId, Vec<BlockId>> {
502605
     let mut children: HashMap<BlockId, Vec<BlockId>> = HashMap::new();
503606
     for (&child, &parent) in idoms {
504607
         children.entry(parent).or_default().push(child);
@@ -522,9 +625,7 @@ pub fn dominator_tree_children(idoms: &HashMap<BlockId, BlockId>)
522625
 /// for every join point `X` (block with ≥ 2 predecessors), walk
523626
 /// each predecessor `P` upward in the dominator tree, adding `X`
524627
 /// to `DF(runner)` until `runner == idom(X)`.
525
-pub fn compute_dominance_frontiers(func: &Function)
526
-    -> HashMap<BlockId, HashSet<BlockId>>
527
-{
628
+pub fn compute_dominance_frontiers(func: &Function) -> HashMap<BlockId, HashSet<BlockId>> {
528629
     let idoms = compute_immediate_dominators(func);
529630
     let preds = predecessors(func);
530631
 
@@ -536,7 +637,9 @@ pub fn compute_dominance_frontiers(func: &Function)
536637
     // unreachable predecessors that downstream consumers (mem2reg's
537638
     // iterated-DF closure in particular) must then defensively
538639
     // ignore. Filtering at the source keeps the DF map clean.
539
-    let reachable: HashSet<BlockId> = idoms.keys().copied()
640
+    let reachable: HashSet<BlockId> = idoms
641
+        .keys()
642
+        .copied()
540643
         .chain(std::iter::once(func.entry))
541644
         .collect();
542645
 
@@ -552,15 +655,20 @@ pub fn compute_dominance_frontiers(func: &Function)
552655
 
553656
     for block in &func.blocks {
554657
         let x = block.id;
555
-        if !reachable.contains(&x) { continue; }
658
+        if !reachable.contains(&x) {
659
+            continue;
660
+        }
556661
         let plist = preds.get(&x).cloned().unwrap_or_default();
557662
         // Drop unreachable predecessors before counting toward
558663
         // "join point" status. An unreachable predecessor adds no
559664
         // runtime control flow into x.
560
-        let plist: Vec<BlockId> = plist.into_iter()
665
+        let plist: Vec<BlockId> = plist
666
+            .into_iter()
561667
             .filter(|p| reachable.contains(p))
562668
             .collect();
563
-        if plist.len() < 2 { continue; }
669
+        if plist.len() < 2 {
670
+            continue;
671
+        }
564672
 
565673
         // `x` is a join point. Walk each predecessor upward.
566674
         let idom_x = idoms.get(&x).copied();
@@ -609,13 +717,17 @@ pub fn dominator_tree_preorder(func: &Function) -> Vec<BlockId> {
609717
 
610718
 #[cfg(test)]
611719
 mod walk_tests {
612
-    use super::*;
613720
     use super::super::types::IrType;
614
-    use crate::lexer::{Span, Position};
721
+    use super::*;
722
+    use crate::lexer::{Position, Span};
615723
 
616724
     fn dummy_span() -> Span {
617725
         let p = Position { line: 1, col: 1 };
618
-        Span { start: p, end: p, file_id: 0 }
726
+        Span {
727
+            start: p,
728
+            end: p,
729
+            file_id: 0,
730
+        }
619731
     }
620732
 
621733
     /// Build a diamond CFG:
@@ -760,21 +872,31 @@ mod walk_tests {
760872
         let entry = f.entry;
761873
         let c0 = f.next_value_id();
762874
         f.block_mut(entry).insts.push(Inst {
763
-            id: c0, kind: InstKind::ConstBool(true),
764
-            ty: IrType::Bool, span: dummy_span(),
875
+            id: c0,
876
+            kind: InstKind::ConstBool(true),
877
+            ty: IrType::Bool,
878
+            span: dummy_span(),
765879
         });
766880
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
767
-            cond: c0, true_dest: a, true_args: vec![],
768
-            false_dest: b, false_args: vec![],
881
+            cond: c0,
882
+            true_dest: a,
883
+            true_args: vec![],
884
+            false_dest: b,
885
+            false_args: vec![],
769886
         });
770887
         let c1 = f.next_value_id();
771888
         f.block_mut(b).insts.push(Inst {
772
-            id: c1, kind: InstKind::ConstBool(true),
773
-            ty: IrType::Bool, span: dummy_span(),
889
+            id: c1,
890
+            kind: InstKind::ConstBool(true),
891
+            ty: IrType::Bool,
892
+            span: dummy_span(),
774893
         });
775894
         f.block_mut(b).terminator = Some(Terminator::CondBranch {
776
-            cond: c1, true_dest: c, true_args: vec![],
777
-            false_dest: d, false_args: vec![],
895
+            cond: c1,
896
+            true_dest: c,
897
+            true_args: vec![],
898
+            false_dest: d,
899
+            false_args: vec![],
778900
         });
779901
         f.block_mut(c).terminator = Some(Terminator::Branch(m1, vec![]));
780902
         f.block_mut(d).terminator = Some(Terminator::Branch(m1, vec![]));
@@ -815,7 +937,10 @@ mod walk_tests {
815937
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
816938
 
817939
         let idoms = compute_immediate_dominators(&f);
818
-        assert!(idoms.is_empty(), "single-block function should have no idoms");
940
+        assert!(
941
+            idoms.is_empty(),
942
+            "single-block function should have no idoms"
943
+        );
819944
 
820945
         let df = compute_dominance_frontiers(&f);
821946
         // Entry is reachable, so it has an entry in the DF map, but
@@ -847,13 +972,18 @@ mod walk_tests {
847972
         let exit = f.create_block("exit");
848973
         f.block_mut(f.entry).terminator = Some(Terminator::CondBranch {
849974
             cond,
850
-            true_dest: f.entry, true_args: vec![],
851
-            false_dest: exit, false_args: vec![],
975
+            true_dest: f.entry,
976
+            true_args: vec![],
977
+            false_dest: exit,
978
+            false_args: vec![],
852979
         });
853980
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
854981
 
855982
         let idoms = compute_immediate_dominators(&f);
856
-        assert!(!idoms.contains_key(&f.entry), "entry has no idom even with a self-edge");
983
+        assert!(
984
+            !idoms.contains_key(&f.entry),
985
+            "entry has no idom even with a self-edge"
986
+        );
857987
         assert_eq!(idoms[&exit], f.entry);
858988
 
859989
         let df = compute_dominance_frontiers(&f);
@@ -861,8 +991,11 @@ mod walk_tests {
861991
         // the implicit "function entry edge" doesn't count, so entry
862992
         // has 1 reachable pred. Not a join point — entry ∉ any DF.
863993
         for (b, frontier) in &df {
864
-            assert!(!frontier.contains(&f.entry),
865
-                "entry should not appear in DF[{:?}]", b);
994
+            assert!(
995
+                !frontier.contains(&f.entry),
996
+                "entry should not appear in DF[{:?}]",
997
+                b
998
+            );
866999
         }
8671000
     }
8681001
 
@@ -889,14 +1022,19 @@ mod walk_tests {
8891022
         });
8901023
         f.block_mut(b).terminator = Some(Terminator::CondBranch {
8911024
             cond,
892
-            true_dest: b, true_args: vec![],
893
-            false_dest: exit, false_args: vec![],
1025
+            true_dest: b,
1026
+            true_args: vec![],
1027
+            false_dest: exit,
1028
+            false_args: vec![],
8941029
         });
8951030
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
8961031
 
8971032
         let df = compute_dominance_frontiers(&f);
898
-        assert_eq!(df[&b], HashSet::from([b]),
899
-            "b's self-edge puts b in its own dominance frontier");
1033
+        assert_eq!(
1034
+            df[&b],
1035
+            HashSet::from([b]),
1036
+            "b's self-edge puts b in its own dominance frontier"
1037
+        );
9001038
         let idoms = compute_immediate_dominators(&f);
9011039
         assert_eq!(idoms[&b], f.entry);
9021040
         assert_eq!(idoms[&exit], b);
@@ -921,13 +1059,17 @@ mod walk_tests {
9211059
         // entry → cond ? a : b
9221060
         let c0 = f.next_value_id();
9231061
         f.block_mut(f.entry).insts.push(Inst {
924
-            id: c0, kind: InstKind::ConstBool(true),
925
-            ty: IrType::Bool, span: dummy_span(),
1062
+            id: c0,
1063
+            kind: InstKind::ConstBool(true),
1064
+            ty: IrType::Bool,
1065
+            span: dummy_span(),
9261066
         });
9271067
         f.block_mut(f.entry).terminator = Some(Terminator::CondBranch {
9281068
             cond: c0,
929
-            true_dest: a, true_args: vec![],
930
-            false_dest: b, false_args: vec![],
1069
+            true_dest: a,
1070
+            true_args: vec![],
1071
+            false_dest: b,
1072
+            false_args: vec![],
9311073
         });
9321074
 
9331075
         // a → b
@@ -938,13 +1080,17 @@ mod walk_tests {
9381080
         //                      bypasses it).
9391081
         let c1 = f.next_value_id();
9401082
         f.block_mut(b).insts.push(Inst {
941
-            id: c1, kind: InstKind::ConstBool(true),
942
-            ty: IrType::Bool, span: dummy_span(),
1083
+            id: c1,
1084
+            kind: InstKind::ConstBool(true),
1085
+            ty: IrType::Bool,
1086
+            span: dummy_span(),
9431087
         });
9441088
         f.block_mut(b).terminator = Some(Terminator::CondBranch {
9451089
             cond: c1,
946
-            true_dest: a, true_args: vec![],
947
-            false_dest: exit, false_args: vec![],
1090
+            true_dest: a,
1091
+            true_args: vec![],
1092
+            false_dest: exit,
1093
+            false_args: vec![],
9481094
         });
9491095
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
9501096
 
src/lexer/mod.rsmodified
1237 lines changed — click to load
@@ -59,36 +59,36 @@ pub enum TokenKind {
5959
     Identifier,
6060
 
6161
     // ---- Operators ----
62
-    Plus,           // +
63
-    Minus,          // -
64
-    Star,           // *
65
-    Slash,          // /
66
-    Power,          // **
67
-    Concat,         // //
68
-    Eq,             // ==
69
-    Ne,             // /=
70
-    Lt,             // <
71
-    Gt,             // >
72
-    Le,             // <=
73
-    Ge,             // >=
62
+    Plus,   // +
63
+    Minus,  // -
64
+    Star,   // *
65
+    Slash,  // /
66
+    Power,  // **
67
+    Concat, // //
68
+    Eq,     // ==
69
+    Ne,     // /=
70
+    Lt,     // <
71
+    Gt,     // >
72
+    Le,     // <=
73
+    Ge,     // >=
7474
     /// .eq. .ne. .lt. .gt. .le. .ge. .and. .or. .not. .eqv. .neqv.
7575
     DotOp(String),
7676
     /// User-defined operator: .myop.
7777
     DefinedOp(String),
7878
 
7979
     // ---- Punctuation ----
80
-    LParen,         // (
81
-    RParen,         // )
82
-    LBracket,       // [
83
-    RBracket,       // ]
84
-    Comma,          // ,
85
-    Colon,          // :
86
-    ColonColon,     // ::
87
-    Semicolon,      // ;
88
-    Percent,        // %
89
-    Arrow,          // =>
90
-    Assign,         // =
91
-    Ampersand,      // & (when not continuation)
80
+    LParen,     // (
81
+    RParen,     // )
82
+    LBracket,   // [
83
+    RBracket,   // ]
84
+    Comma,      // ,
85
+    Colon,      // :
86
+    ColonColon, // ::
87
+    Semicolon,  // ;
88
+    Percent,    // %
89
+    Arrow,      // =>
90
+    Assign,     // =
91
+    Ampersand,  // & (when not continuation)
9292
 
9393
     // ---- Special ----
9494
     Newline,
@@ -144,34 +144,123 @@ impl fmt::Display for TokenKind {
144144
 /// The lexer provides `is_keyword()` as a helper.
145145
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
146146
 pub enum Keyword {
147
-    Program, EndProgram, Module, EndModule, Submodule, EndSubmodule,
148
-    Subroutine, EndSubroutine, Function, EndFunction, BlockData, EndBlockData,
149
-    Contains, Use, Only, Import,
150
-    Implicit, None,
151
-    Integer, Real, DoublePrecision, DoubleComplex, Complex, Character, Logical, Type, Class,
152
-    Dimension, Allocatable, Pointer, Target, Intent, In, Out, InOut,
153
-    Optional, Save, Parameter, Value, Volatile, Asynchronous, Protected,
154
-    Contiguous, External, Intrinsic, Bind,
155
-    Public, Private,
156
-    If, Then, Else, ElseIf, EndIf,
157
-    Do, EndDo, While, Concurrent,
158
-    Select, Case, EndSelect, Default,
159
-    Where, EndWhere, Elsewhere,
160
-    Forall, EndForall,
161
-    Block, EndBlock,
162
-    Associate, EndAssociate,
163
-    Critical, EndCritical,
147
+    Program,
148
+    EndProgram,
149
+    Module,
150
+    EndModule,
151
+    Submodule,
152
+    EndSubmodule,
153
+    Subroutine,
154
+    EndSubroutine,
155
+    Function,
156
+    EndFunction,
157
+    BlockData,
158
+    EndBlockData,
159
+    Contains,
160
+    Use,
161
+    Only,
162
+    Import,
163
+    Implicit,
164
+    None,
165
+    Integer,
166
+    Real,
167
+    DoublePrecision,
168
+    DoubleComplex,
169
+    Complex,
170
+    Character,
171
+    Logical,
172
+    Type,
173
+    Class,
174
+    Dimension,
175
+    Allocatable,
176
+    Pointer,
177
+    Target,
178
+    Intent,
179
+    In,
180
+    Out,
181
+    InOut,
182
+    Optional,
183
+    Save,
184
+    Parameter,
185
+    Value,
186
+    Volatile,
187
+    Asynchronous,
188
+    Protected,
189
+    Contiguous,
190
+    External,
191
+    Intrinsic,
192
+    Bind,
193
+    Public,
194
+    Private,
195
+    If,
196
+    Then,
197
+    Else,
198
+    ElseIf,
199
+    EndIf,
200
+    Do,
201
+    EndDo,
202
+    While,
203
+    Concurrent,
204
+    Select,
205
+    Case,
206
+    EndSelect,
207
+    Default,
208
+    Where,
209
+    EndWhere,
210
+    Elsewhere,
211
+    Forall,
212
+    EndForall,
213
+    Block,
214
+    EndBlock,
215
+    Associate,
216
+    EndAssociate,
217
+    Critical,
218
+    EndCritical,
164219
     Continue,
165
-    Exit, Cycle, Stop, ErrorStop, Return, GoTo,
166
-    Call, Print, Write, Read, Open, Close, Inquire,
167
-    Rewind, Backspace, Endfile, Flush, Wait,
168
-    Allocate, Deallocate, Nullify,
169
-    Data, Common, Equivalence, Namelist, Sequence,
220
+    Exit,
221
+    Cycle,
222
+    Stop,
223
+    ErrorStop,
224
+    Return,
225
+    GoTo,
226
+    Call,
227
+    Print,
228
+    Write,
229
+    Read,
230
+    Open,
231
+    Close,
232
+    Inquire,
233
+    Rewind,
234
+    Backspace,
235
+    Endfile,
236
+    Flush,
237
+    Wait,
238
+    Allocate,
239
+    Deallocate,
240
+    Nullify,
241
+    Data,
242
+    Common,
243
+    Equivalence,
244
+    Namelist,
245
+    Sequence,
170246
     Format,
171
-    Pure, Impure, Elemental, Recursive, NonRecursive,
172
-    Abstract, Interface, EndInterface, Procedure, Generic, Operator, Assignment,
173
-    Entry, Result,
174
-    Enum, Enumerator, EndEnum,
247
+    Pure,
248
+    Impure,
249
+    Elemental,
250
+    Recursive,
251
+    NonRecursive,
252
+    Abstract,
253
+    Interface,
254
+    EndInterface,
255
+    Procedure,
256
+    Generic,
257
+    Operator,
258
+    Assignment,
259
+    Entry,
260
+    Result,
261
+    Enum,
262
+    Enumerator,
263
+    EndEnum,
175264
     End,
176265
 }
177266
 
@@ -303,10 +392,21 @@ pub fn is_keyword(name: &str) -> Option<Keyword> {
303392
 // ---- Known dot-operators ----
304393
 
305394
 fn is_known_dot_op(name: &str) -> bool {
306
-    matches!(name.to_lowercase().as_str(),
307
-        "and" | "or" | "not" | "eqv" | "neqv" |
308
-        "eq" | "ne" | "lt" | "gt" | "le" | "ge" |
309
-        "true" | "false"
395
+    matches!(
396
+        name.to_lowercase().as_str(),
397
+        "and"
398
+            | "or"
399
+            | "not"
400
+            | "eqv"
401
+            | "neqv"
402
+            | "eq"
403
+            | "ne"
404
+            | "lt"
405
+            | "gt"
406
+            | "le"
407
+            | "ge"
408
+            | "true"
409
+            | "false"
310410
     )
311411
 }
312412
 
@@ -320,7 +420,11 @@ pub struct LexError {
320420
 
321421
 impl fmt::Display for LexError {
322422
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323
-        write!(f, "{}:{}: error: {}", self.span.start.line, self.span.start.col, self.msg)
423
+        write!(
424
+            f,
425
+            "{}:{}: error: {}",
426
+            self.span.start.line, self.span.start.col, self.msg
427
+        )
324428
     }
325429
 }
326430
 
@@ -371,7 +475,13 @@ pub struct Lexer<'a> {
371475
 
372476
 impl<'a> Lexer<'a> {
373477
     pub fn new(src: &'a str, file_id: u32) -> Self {
374
-        Self { src: src.as_bytes(), pos: 0, line: 1, col: 1, file_id }
478
+        Self {
479
+            src: src.as_bytes(),
480
+            pos: 0,
481
+            line: 1,
482
+            col: 1,
483
+            file_id,
484
+        }
375485
     }
376486
 
377487
     /// Tokenize the entire source into a Vec.
@@ -382,29 +492,49 @@ impl<'a> Lexer<'a> {
382492
             let tok = lexer.next_token()?;
383493
             let is_eof = tok.kind == TokenKind::Eof;
384494
             tokens.push(tok);
385
-            if is_eof { break; }
495
+            if is_eof {
496
+                break;
497
+            }
386498
         }
387499
         Ok(tokens)
388500
     }
389501
 
390502
     fn pos(&self) -> Position {
391
-        Position { line: self.line, col: self.col }
503
+        Position {
504
+            line: self.line,
505
+            col: self.col,
506
+        }
392507
     }
393508
 
394509
     fn span_from(&self, start: Position) -> Span {
395
-        Span { file_id: self.file_id, start, end: self.pos() }
510
+        Span {
511
+            file_id: self.file_id,
512
+            start,
513
+            end: self.pos(),
514
+        }
396515
     }
397516
 
398517
     fn err(&self, start: Position, msg: String) -> LexError {
399
-        LexError { span: self.span_from(start), msg }
518
+        LexError {
519
+            span: self.span_from(start),
520
+            msg,
521
+        }
400522
     }
401523
 
402524
     fn peek(&self) -> u8 {
403
-        if self.pos < self.src.len() { self.src[self.pos] } else { 0 }
525
+        if self.pos < self.src.len() {
526
+            self.src[self.pos]
527
+        } else {
528
+            0
529
+        }
404530
     }
405531
 
406532
     fn peek2(&self) -> u8 {
407
-        if self.pos + 1 < self.src.len() { self.src[self.pos + 1] } else { 0 }
533
+        if self.pos + 1 < self.src.len() {
534
+            self.src[self.pos + 1]
535
+        } else {
536
+            0
537
+        }
408538
     }
409539
 
410540
     fn advance(&mut self) -> u8 {
@@ -432,7 +562,9 @@ impl<'a> Lexer<'a> {
432562
     /// Skip a continuation: & at end of line, optional comment, newline, optional leading &.
433563
     /// Returns true if a continuation was consumed.
434564
     fn try_continuation(&mut self) -> bool {
435
-        if self.peek() != b'&' { return false; }
565
+        if self.peek() != b'&' {
566
+            return false;
567
+        }
436568
 
437569
         // Save position in case this isn't a continuation.
438570
         let save_pos = self.pos;
@@ -487,7 +619,9 @@ impl<'a> Lexer<'a> {
487619
                 while !self.at_end() && self.peek() != b'\n' {
488620
                     self.advance();
489621
                 }
490
-                if !self.at_end() { self.advance(); }
622
+                if !self.at_end() {
623
+                    self.advance();
624
+                }
491625
                 continue;
492626
             }
493627
             break;
@@ -600,17 +734,17 @@ impl<'a> Lexer<'a> {
600734
                 let save_col = self.col;
601735
 
602736
                 self.advance(); // &
603
-                // String-continuation check. A lone `&` ending the
604
-                // current physical line (optionally with trailing
605
-                // whitespace and/or a `!comment`) continues the
606
-                // string on the next line. Anything else — notably a
607
-                // closing quote before the newline — means the `&`
608
-                // is a literal character of the string.
609
-                //
610
-                // Scan from the current pos without committing: find
611
-                // the earliest of quote, `!`, or newline. Only newline
612
-                // (possibly preceded by whitespace or a comment) keeps
613
-                // is_cont true.
737
+                                // String-continuation check. A lone `&` ending the
738
+                                // current physical line (optionally with trailing
739
+                                // whitespace and/or a `!comment`) continues the
740
+                                // string on the next line. Anything else — notably a
741
+                                // closing quote before the newline — means the `&`
742
+                                // is a literal character of the string.
743
+                                //
744
+                                // Scan from the current pos without committing: find
745
+                                // the earliest of quote, `!`, or newline. Only newline
746
+                                // (possibly preceded by whitespace or a comment) keeps
747
+                                // is_cont true.
614748
                 let mut is_cont = false;
615749
                 let mut scan = self.pos;
616750
                 let src_bytes = self.src;
@@ -669,7 +803,9 @@ impl<'a> Lexer<'a> {
669803
                 if is_cont && !self.at_end() {
670804
                     self.advance(); // newline
671805
                     self.skip_spaces();
672
-                    if self.peek() == b'&' { self.advance(); }
806
+                    if self.peek() == b'&' {
807
+                        self.advance();
808
+                    }
673809
                     continue;
674810
                 }
675811
                 // Not a continuation — restore and treat & as literal character.
@@ -731,7 +867,11 @@ impl<'a> Lexer<'a> {
731867
                 // Could be 1.0e5 (exponent) or 1.eq.2 (dot-operator).
732868
                 // Lookahead past the e/d: if next is digit or +/-, it's an exponent.
733869
                 // If it's another letter (like 'q' in 'eq'), it's a dot-operator.
734
-                let after_ed = if self.pos + 2 < self.src.len() { self.src[self.pos + 2] } else { 0 };
870
+                let after_ed = if self.pos + 2 < self.src.len() {
871
+                    self.src[self.pos + 2]
872
+                } else {
873
+                    0
874
+                };
735875
                 matches!(after_ed, b'0'..=b'9' | b'+' | b'-')
736876
             } else if !next.is_ascii_alphabetic() {
737877
                 // 5. followed by space/operator/newline/EOF — trailing dot real.
@@ -781,7 +921,11 @@ impl<'a> Lexer<'a> {
781921
         }
782922
 
783923
         Ok(Token {
784
-            kind: if is_real { TokenKind::RealLiteral } else { TokenKind::IntegerLiteral },
924
+            kind: if is_real {
925
+                TokenKind::RealLiteral
926
+            } else {
927
+                TokenKind::IntegerLiteral
928
+            },
785929
             text,
786930
             span: self.span_from(start),
787931
         })
@@ -830,7 +974,11 @@ impl<'a> Lexer<'a> {
830974
                 return Ok(Token {
831975
                     kind: TokenKind::Identifier,
832976
                     text: "..".into(),
833
-                    span: Span { start, end: self.pos(), file_id: self.file_id },
977
+                    span: Span {
978
+                        start,
979
+                        end: self.pos(),
980
+                        file_id: self.file_id,
981
+                    },
834982
                 });
835983
             }
836984
             return Err(self.err(start, "unexpected '.'".into()));
@@ -904,24 +1052,48 @@ impl<'a> Lexer<'a> {
9041052
         let (kind, text) = match ch {
9051053
             b'+' => (TokenKind::Plus, "+"),
9061054
             b'-' => (TokenKind::Minus, "-"),
907
-            b'*' if next == b'*' => { self.advance(); (TokenKind::Power, "**") }
1055
+            b'*' if next == b'*' => {
1056
+                self.advance();
1057
+                (TokenKind::Power, "**")
1058
+            }
9081059
             b'*' => (TokenKind::Star, "*"),
909
-            b'/' if next == b'/' => { self.advance(); (TokenKind::Concat, "//") }
910
-            b'/' if next == b'=' => { self.advance(); (TokenKind::Ne, "/=") }
1060
+            b'/' if next == b'/' => {
1061
+                self.advance();
1062
+                (TokenKind::Concat, "//")
1063
+            }
1064
+            b'/' if next == b'=' => {
1065
+                self.advance();
1066
+                (TokenKind::Ne, "/=")
1067
+            }
9111068
             b'/' => (TokenKind::Slash, "/"),
912
-            b'=' if next == b'=' => { self.advance(); (TokenKind::Eq, "==") }
913
-            b'=' if next == b'>' => { self.advance(); (TokenKind::Arrow, "=>") }
1069
+            b'=' if next == b'=' => {
1070
+                self.advance();
1071
+                (TokenKind::Eq, "==")
1072
+            }
1073
+            b'=' if next == b'>' => {
1074
+                self.advance();
1075
+                (TokenKind::Arrow, "=>")
1076
+            }
9141077
             b'=' => (TokenKind::Assign, "="),
915
-            b'<' if next == b'=' => { self.advance(); (TokenKind::Le, "<=") }
1078
+            b'<' if next == b'=' => {
1079
+                self.advance();
1080
+                (TokenKind::Le, "<=")
1081
+            }
9161082
             b'<' => (TokenKind::Lt, "<"),
917
-            b'>' if next == b'=' => { self.advance(); (TokenKind::Ge, ">=") }
1083
+            b'>' if next == b'=' => {
1084
+                self.advance();
1085
+                (TokenKind::Ge, ">=")
1086
+            }
9181087
             b'>' => (TokenKind::Gt, ">"),
9191088
             b'(' => (TokenKind::LParen, "("),
9201089
             b')' => (TokenKind::RParen, ")"),
9211090
             b'[' => (TokenKind::LBracket, "["),
9221091
             b']' => (TokenKind::RBracket, "]"),
9231092
             b',' => (TokenKind::Comma, ","),
924
-            b':' if next == b':' => { self.advance(); (TokenKind::ColonColon, "::") }
1093
+            b':' if next == b':' => {
1094
+                self.advance();
1095
+                (TokenKind::ColonColon, "::")
1096
+            }
9251097
             b':' => (TokenKind::Colon, ":"),
9261098
             b';' => (TokenKind::Semicolon, ";"),
9271099
             b'%' => (TokenKind::Percent, "%"),
@@ -948,11 +1120,19 @@ mod tests {
9481120
     }
9491121
 
9501122
     fn kinds(src: &str) -> Vec<TokenKind> {
951
-        toks(src).into_iter().map(|t| t.kind).filter(|k| !matches!(k, TokenKind::Eof)).collect()
1123
+        toks(src)
1124
+            .into_iter()
1125
+            .map(|t| t.kind)
1126
+            .filter(|k| !matches!(k, TokenKind::Eof))
1127
+            .collect()
9521128
     }
9531129
 
9541130
     fn texts(src: &str) -> Vec<String> {
955
-        toks(src).into_iter().map(|t| t.text).filter(|t| !t.is_empty()).collect()
1131
+        toks(src)
1132
+            .into_iter()
1133
+            .map(|t| t.text)
1134
+            .filter(|t| !t.is_empty())
1135
+            .collect()
9561136
     }
9571137
 
9581138
     // ---- Identifiers ----
@@ -972,10 +1152,15 @@ mod tests {
9721152
     fn keyword_is_identifier() {
9731153
         // Keywords are not reserved — lexed as identifiers.
9741154
         let toks = kinds("integer real do if");
975
-        assert_eq!(toks, vec![
976
-            TokenKind::Identifier, TokenKind::Identifier,
977
-            TokenKind::Identifier, TokenKind::Identifier,
978
-        ]);
1155
+        assert_eq!(
1156
+            toks,
1157
+            vec![
1158
+                TokenKind::Identifier,
1159
+                TokenKind::Identifier,
1160
+                TokenKind::Identifier,
1161
+                TokenKind::Identifier,
1162
+            ]
1163
+        );
9791164
     }
9801165
 
9811166
     #[test]
@@ -1158,9 +1343,15 @@ mod tests {
11581343
 
11591344
     #[test]
11601345
     fn arithmetic_operators() {
1161
-        assert_eq!(kinds("+ - * /"), vec![
1162
-            TokenKind::Plus, TokenKind::Minus, TokenKind::Star, TokenKind::Slash,
1163
-        ]);
1346
+        assert_eq!(
1347
+            kinds("+ - * /"),
1348
+            vec![
1349
+                TokenKind::Plus,
1350
+                TokenKind::Minus,
1351
+                TokenKind::Star,
1352
+                TokenKind::Slash,
1353
+            ]
1354
+        );
11641355
     }
11651356
 
11661357
     #[test]
@@ -1175,34 +1366,55 @@ mod tests {
11751366
 
11761367
     #[test]
11771368
     fn comparison_operators() {
1178
-        assert_eq!(kinds("== /= < > <= >="), vec![
1179
-            TokenKind::Eq, TokenKind::Ne, TokenKind::Lt, TokenKind::Gt,
1180
-            TokenKind::Le, TokenKind::Ge,
1181
-        ]);
1369
+        assert_eq!(
1370
+            kinds("== /= < > <= >="),
1371
+            vec![
1372
+                TokenKind::Eq,
1373
+                TokenKind::Ne,
1374
+                TokenKind::Lt,
1375
+                TokenKind::Gt,
1376
+                TokenKind::Le,
1377
+                TokenKind::Ge,
1378
+            ]
1379
+        );
11821380
     }
11831381
 
11841382
     #[test]
11851383
     fn dot_comparison_operators() {
1186
-        assert_eq!(kinds(".eq. .ne. .lt. .gt. .le. .ge."), vec![
1187
-            TokenKind::DotOp("eq".into()), TokenKind::DotOp("ne".into()),
1188
-            TokenKind::DotOp("lt".into()), TokenKind::DotOp("gt".into()),
1189
-            TokenKind::DotOp("le".into()), TokenKind::DotOp("ge".into()),
1190
-        ]);
1384
+        assert_eq!(
1385
+            kinds(".eq. .ne. .lt. .gt. .le. .ge."),
1386
+            vec![
1387
+                TokenKind::DotOp("eq".into()),
1388
+                TokenKind::DotOp("ne".into()),
1389
+                TokenKind::DotOp("lt".into()),
1390
+                TokenKind::DotOp("gt".into()),
1391
+                TokenKind::DotOp("le".into()),
1392
+                TokenKind::DotOp("ge".into()),
1393
+            ]
1394
+        );
11911395
     }
11921396
 
11931397
     #[test]
11941398
     fn dot_logical_operators() {
1195
-        assert_eq!(kinds(".and. .or. .not."), vec![
1196
-            TokenKind::DotOp("and".into()), TokenKind::DotOp("or".into()),
1197
-            TokenKind::DotOp("not".into()),
1198
-        ]);
1399
+        assert_eq!(
1400
+            kinds(".and. .or. .not."),
1401
+            vec![
1402
+                TokenKind::DotOp("and".into()),
1403
+                TokenKind::DotOp("or".into()),
1404
+                TokenKind::DotOp("not".into()),
1405
+            ]
1406
+        );
11991407
     }
12001408
 
12011409
     #[test]
12021410
     fn dot_eqv_neqv() {
1203
-        assert_eq!(kinds(".eqv. .neqv."), vec![
1204
-            TokenKind::DotOp("eqv".into()), TokenKind::DotOp("neqv".into()),
1205
-        ]);
1411
+        assert_eq!(
1412
+            kinds(".eqv. .neqv."),
1413
+            vec![
1414
+                TokenKind::DotOp("eqv".into()),
1415
+                TokenKind::DotOp("neqv".into()),
1416
+            ]
1417
+        );
12061418
     }
12071419
 
12081420
     #[test]
@@ -1214,11 +1426,19 @@ mod tests {
12141426
 
12151427
     #[test]
12161428
     fn punctuation() {
1217
-        assert_eq!(kinds("( ) [ ] , : ; %"), vec![
1218
-            TokenKind::LParen, TokenKind::RParen,
1219
-            TokenKind::LBracket, TokenKind::RBracket,
1220
-            TokenKind::Comma, TokenKind::Colon, TokenKind::Semicolon, TokenKind::Percent,
1221
-        ]);
1429
+        assert_eq!(
1430
+            kinds("( ) [ ] , : ; %"),
1431
+            vec![
1432
+                TokenKind::LParen,
1433
+                TokenKind::RParen,
1434
+                TokenKind::LBracket,
1435
+                TokenKind::RBracket,
1436
+                TokenKind::Comma,
1437
+                TokenKind::Colon,
1438
+                TokenKind::Semicolon,
1439
+                TokenKind::Percent,
1440
+            ]
1441
+        );
12221442
     }
12231443
 
12241444
     #[test]
@@ -1249,16 +1469,26 @@ mod tests {
12491469
 
12501470
     #[test]
12511471
     fn newline_is_statement_terminator() {
1252
-        assert_eq!(kinds("x\ny"), vec![
1253
-            TokenKind::Identifier, TokenKind::Newline, TokenKind::Identifier,
1254
-        ]);
1472
+        assert_eq!(
1473
+            kinds("x\ny"),
1474
+            vec![
1475
+                TokenKind::Identifier,
1476
+                TokenKind::Newline,
1477
+                TokenKind::Identifier,
1478
+            ]
1479
+        );
12551480
     }
12561481
 
12571482
     #[test]
12581483
     fn semicolon_is_statement_separator() {
1259
-        assert_eq!(kinds("x; y"), vec![
1260
-            TokenKind::Identifier, TokenKind::Semicolon, TokenKind::Identifier,
1261
-        ]);
1484
+        assert_eq!(
1485
+            kinds("x; y"),
1486
+            vec![
1487
+                TokenKind::Identifier,
1488
+                TokenKind::Semicolon,
1489
+                TokenKind::Identifier,
1490
+            ]
1491
+        );
12621492
     }
12631493
 
12641494
     // ---- Continuation lines ----
@@ -1266,19 +1496,40 @@ mod tests {
12661496
     #[test]
12671497
     fn continuation_joins_tokens() {
12681498
         let k = kinds("x + &\n  y");
1269
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
1499
+        assert_eq!(
1500
+            k,
1501
+            vec![
1502
+                TokenKind::Identifier,
1503
+                TokenKind::Plus,
1504
+                TokenKind::Identifier
1505
+            ]
1506
+        );
12701507
     }
12711508
 
12721509
     #[test]
12731510
     fn continuation_with_leading_ampersand() {
12741511
         let k = kinds("x + &\n  &y");
1275
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
1512
+        assert_eq!(
1513
+            k,
1514
+            vec![
1515
+                TokenKind::Identifier,
1516
+                TokenKind::Plus,
1517
+                TokenKind::Identifier
1518
+            ]
1519
+        );
12761520
     }
12771521
 
12781522
     #[test]
12791523
     fn continuation_with_comment() {
12801524
         let k = kinds("x + & ! comment\n  y");
1281
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
1525
+        assert_eq!(
1526
+            k,
1527
+            vec![
1528
+                TokenKind::Identifier,
1529
+                TokenKind::Plus,
1530
+                TokenKind::Identifier
1531
+            ]
1532
+        );
12821533
     }
12831534
 
12841535
     // ---- Source locations ----
@@ -1299,34 +1550,64 @@ mod tests {
12991550
     #[test]
13001551
     fn complex_declaration() {
13011552
         let k = kinds("integer, allocatable :: x(:,:)");
1302
-        assert_eq!(k, vec![
1303
-            TokenKind::Identifier, TokenKind::Comma, TokenKind::Identifier,
1304
-            TokenKind::ColonColon,
1305
-            TokenKind::Identifier, TokenKind::LParen, TokenKind::Colon,
1306
-            TokenKind::Comma, TokenKind::Colon, TokenKind::RParen,
1307
-        ]);
1553
+        assert_eq!(
1554
+            k,
1555
+            vec![
1556
+                TokenKind::Identifier,
1557
+                TokenKind::Comma,
1558
+                TokenKind::Identifier,
1559
+                TokenKind::ColonColon,
1560
+                TokenKind::Identifier,
1561
+                TokenKind::LParen,
1562
+                TokenKind::Colon,
1563
+                TokenKind::Comma,
1564
+                TokenKind::Colon,
1565
+                TokenKind::RParen,
1566
+            ]
1567
+        );
13081568
     }
13091569
 
13101570
     #[test]
13111571
     fn pointer_assignment() {
13121572
         let k = kinds("ptr => target");
1313
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Arrow, TokenKind::Identifier]);
1573
+        assert_eq!(
1574
+            k,
1575
+            vec![
1576
+                TokenKind::Identifier,
1577
+                TokenKind::Arrow,
1578
+                TokenKind::Identifier
1579
+            ]
1580
+        );
13141581
     }
13151582
 
13161583
     #[test]
13171584
     fn component_access() {
13181585
         let k = kinds("obj%member");
1319
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Percent, TokenKind::Identifier]);
1586
+        assert_eq!(
1587
+            k,
1588
+            vec![
1589
+                TokenKind::Identifier,
1590
+                TokenKind::Percent,
1591
+                TokenKind::Identifier
1592
+            ]
1593
+        );
13201594
     }
13211595
 
13221596
     #[test]
13231597
     fn array_constructor_bracket() {
13241598
         let k = kinds("[1, 2, 3]");
1325
-        assert_eq!(k, vec![
1326
-            TokenKind::LBracket, TokenKind::IntegerLiteral, TokenKind::Comma,
1327
-            TokenKind::IntegerLiteral, TokenKind::Comma, TokenKind::IntegerLiteral,
1328
-            TokenKind::RBracket,
1329
-        ]);
1599
+        assert_eq!(
1600
+            k,
1601
+            vec![
1602
+                TokenKind::LBracket,
1603
+                TokenKind::IntegerLiteral,
1604
+                TokenKind::Comma,
1605
+                TokenKind::IntegerLiteral,
1606
+                TokenKind::Comma,
1607
+                TokenKind::IntegerLiteral,
1608
+                TokenKind::RBracket,
1609
+            ]
1610
+        );
13301611
     }
13311612
 
13321613
     // ---- Ambiguity cases from spec ----
@@ -1341,9 +1622,14 @@ mod tests {
13411622
     #[test]
13421623
     fn integer_dot_and_with_spaces() {
13431624
         let k = kinds("a .and. b");
1344
-        assert_eq!(k, vec![
1345
-            TokenKind::Identifier, TokenKind::DotOp("and".into()), TokenKind::Identifier,
1346
-        ]);
1625
+        assert_eq!(
1626
+            k,
1627
+            vec![
1628
+                TokenKind::Identifier,
1629
+                TokenKind::DotOp("and".into()),
1630
+                TokenKind::Identifier,
1631
+            ]
1632
+        );
13471633
     }
13481634
 
13491635
     #[test]
@@ -1351,25 +1637,40 @@ mod tests {
13511637
         // Critical ambiguity: 1.eq.2 must NOT be parsed as a real with exponent.
13521638
         // It's: integer(1), .eq., integer(2)
13531639
         let k = kinds("1.eq.2");
1354
-        assert_eq!(k, vec![
1355
-            TokenKind::IntegerLiteral, TokenKind::DotOp("eq".into()), TokenKind::IntegerLiteral,
1356
-        ]);
1640
+        assert_eq!(
1641
+            k,
1642
+            vec![
1643
+                TokenKind::IntegerLiteral,
1644
+                TokenKind::DotOp("eq".into()),
1645
+                TokenKind::IntegerLiteral,
1646
+            ]
1647
+        );
13571648
     }
13581649
 
13591650
     #[test]
13601651
     fn integer_dot_and_no_spaces() {
13611652
         let k = kinds("1.and.2");
1362
-        assert_eq!(k, vec![
1363
-            TokenKind::IntegerLiteral, TokenKind::DotOp("and".into()), TokenKind::IntegerLiteral,
1364
-        ]);
1653
+        assert_eq!(
1654
+            k,
1655
+            vec![
1656
+                TokenKind::IntegerLiteral,
1657
+                TokenKind::DotOp("and".into()),
1658
+                TokenKind::IntegerLiteral,
1659
+            ]
1660
+        );
13651661
     }
13661662
 
13671663
     #[test]
13681664
     fn integer_dot_ne_no_spaces() {
13691665
         let k = kinds("x.ne.y");
1370
-        assert_eq!(k, vec![
1371
-            TokenKind::Identifier, TokenKind::DotOp("ne".into()), TokenKind::Identifier,
1372
-        ]);
1666
+        assert_eq!(
1667
+            k,
1668
+            vec![
1669
+                TokenKind::Identifier,
1670
+                TokenKind::DotOp("ne".into()),
1671
+                TokenKind::Identifier,
1672
+            ]
1673
+        );
13731674
     }
13741675
 
13751676
     #[test]
@@ -1396,9 +1697,14 @@ mod tests {
13961697
     fn five_dot_eq_three() {
13971698
         // 5.eq.3 — integer, .eq., integer (not a real)
13981699
         let k = kinds("5.eq.3");
1399
-        assert_eq!(k, vec![
1400
-            TokenKind::IntegerLiteral, TokenKind::DotOp("eq".into()), TokenKind::IntegerLiteral,
1401
-        ]);
1700
+        assert_eq!(
1701
+            k,
1702
+            vec![
1703
+                TokenKind::IntegerLiteral,
1704
+                TokenKind::DotOp("eq".into()),
1705
+                TokenKind::IntegerLiteral,
1706
+            ]
1707
+        );
14021708
     }
14031709
 
14041710
     // ---- Error cases ----
@@ -1428,9 +1734,20 @@ program hello
14281734
 end program hello
14291735
 ";
14301736
         let tokens = Lexer::tokenize(src, 0).unwrap();
1431
-        let ident_count = tokens.iter().filter(|t| t.kind == TokenKind::Identifier).count();
1432
-        assert!(ident_count >= 8, "expected 8+ identifiers, got {}", ident_count);
1433
-        let last_non_eof = tokens.iter().rev().find(|t| t.kind != TokenKind::Eof && t.kind != TokenKind::Newline).unwrap();
1737
+        let ident_count = tokens
1738
+            .iter()
1739
+            .filter(|t| t.kind == TokenKind::Identifier)
1740
+            .count();
1741
+        assert!(
1742
+            ident_count >= 8,
1743
+            "expected 8+ identifiers, got {}",
1744
+            ident_count
1745
+        );
1746
+        let last_non_eof = tokens
1747
+            .iter()
1748
+            .rev()
1749
+            .find(|t| t.kind != TokenKind::Eof && t.kind != TokenKind::Newline)
1750
+            .unwrap();
14341751
         assert_eq!(last_non_eof.text, "hello");
14351752
     }
14361753
 
@@ -1438,17 +1755,22 @@ end program hello
14381755
 
14391756
     /// Try to tokenize a fortsh source file. Strips preprocessor directives first.
14401757
     fn try_lex_fortsh_file(path: &str) -> Result<usize, String> {
1441
-        let src = std::fs::read_to_string(path)
1442
-            .map_err(|e| format!("{}: {}", path, e))?;
1758
+        let src = std::fs::read_to_string(path).map_err(|e| format!("{}: {}", path, e))?;
14431759
 
14441760
         // Strip preprocessor directives (lexer expects preprocessed input).
1445
-        let filtered: String = src.lines()
1446
-            .map(|line| if line.trim_start().starts_with('#') { "" } else { line })
1761
+        let filtered: String = src
1762
+            .lines()
1763
+            .map(|line| {
1764
+                if line.trim_start().starts_with('#') {
1765
+                    ""
1766
+                } else {
1767
+                    line
1768
+                }
1769
+            })
14471770
             .collect::<Vec<_>>()
14481771
             .join("\n");
14491772
 
1450
-        let tokens = Lexer::tokenize(&filtered, 0)
1451
-            .map_err(|e| format!("{}: {}", path, e))?;
1773
+        let tokens = Lexer::tokenize(&filtered, 0).map_err(|e| format!("{}: {}", path, e))?;
14521774
 
14531775
         Ok(tokens.len())
14541776
     }
@@ -1545,12 +1867,18 @@ end program hello
15451867
     #[test]
15461868
     fn multiple_continuations() {
15471869
         let k = kinds("x = a + &\n    b + &\n    c");
1548
-        assert_eq!(k, vec![
1549
-            TokenKind::Identifier, TokenKind::Assign,
1550
-            TokenKind::Identifier, TokenKind::Plus,
1551
-            TokenKind::Identifier, TokenKind::Plus,
1552
-            TokenKind::Identifier,
1553
-        ]);
1870
+        assert_eq!(
1871
+            k,
1872
+            vec![
1873
+                TokenKind::Identifier,
1874
+                TokenKind::Assign,
1875
+                TokenKind::Identifier,
1876
+                TokenKind::Plus,
1877
+                TokenKind::Identifier,
1878
+                TokenKind::Plus,
1879
+                TokenKind::Identifier,
1880
+            ]
1881
+        );
15541882
     }
15551883
 
15561884
     #[test]
@@ -1575,11 +1903,17 @@ end program hello
15751903
     #[test]
15761904
     fn spec_ambiguity_real_function_call() {
15771905
         let k = kinds("x = real(i)");
1578
-        assert_eq!(k, vec![
1579
-            TokenKind::Identifier, TokenKind::Assign,
1580
-            TokenKind::Identifier, TokenKind::LParen,
1581
-            TokenKind::Identifier, TokenKind::RParen,
1582
-        ]);
1906
+        assert_eq!(
1907
+            k,
1908
+            vec![
1909
+                TokenKind::Identifier,
1910
+                TokenKind::Assign,
1911
+                TokenKind::Identifier,
1912
+                TokenKind::LParen,
1913
+                TokenKind::Identifier,
1914
+                TokenKind::RParen,
1915
+            ]
1916
+        );
15831917
     }
15841918
 
15851919
     #[test]
@@ -1595,7 +1929,8 @@ end program hello
15951929
         assert!(k.contains(&TokenKind::Comma));
15961930
         // "do" and "i" are both identifiers.
15971931
         let tokens = toks("do i = 1, 10");
1598
-        let idents: Vec<_> = tokens.iter()
1932
+        let idents: Vec<_> = tokens
1933
+            .iter()
15991934
             .filter(|t| t.kind == TokenKind::Identifier)
16001935
             .map(|t| t.text.as_str())
16011936
             .collect();
@@ -1606,9 +1941,14 @@ end program hello
16061941
     #[test]
16071942
     fn spec_ambiguity_do_as_variable() {
16081943
         let k = kinds("do = 3.14");
1609
-        assert_eq!(k, vec![
1610
-            TokenKind::Identifier, TokenKind::Assign, TokenKind::RealLiteral,
1611
-        ]);
1944
+        assert_eq!(
1945
+            k,
1946
+            vec![
1947
+                TokenKind::Identifier,
1948
+                TokenKind::Assign,
1949
+                TokenKind::RealLiteral,
1950
+            ]
1951
+        );
16121952
         assert_eq!(toks("do = 3.14")[0].text, "do");
16131953
     }
16141954
 
@@ -1629,11 +1969,18 @@ end program hello
16291969
     #[test]
16301970
     fn semicolon_separates_statements() {
16311971
         let k = kinds("x = 1; y = 2");
1632
-        assert_eq!(k, vec![
1633
-            TokenKind::Identifier, TokenKind::Assign, TokenKind::IntegerLiteral,
1634
-            TokenKind::Semicolon,
1635
-            TokenKind::Identifier, TokenKind::Assign, TokenKind::IntegerLiteral,
1636
-        ]);
1972
+        assert_eq!(
1973
+            k,
1974
+            vec![
1975
+                TokenKind::Identifier,
1976
+                TokenKind::Assign,
1977
+                TokenKind::IntegerLiteral,
1978
+                TokenKind::Semicolon,
1979
+                TokenKind::Identifier,
1980
+                TokenKind::Assign,
1981
+                TokenKind::IntegerLiteral,
1982
+            ]
1983
+        );
16371984
     }
16381985
 
16391986
     // ---- Performance ----
@@ -1642,7 +1989,9 @@ end program hello
16421989
     fn performance_fortsh_under_one_second() {
16431990
         let src_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../fortsh/src");
16441991
         let root = std::path::Path::new(src_dir);
1645
-        if !root.exists() { return; }
1992
+        if !root.exists() {
1993
+            return;
1994
+        }
16461995
 
16471996
         // Collect all source.
16481997
         let mut all_source = String::new();
@@ -1650,12 +1999,21 @@ end program hello
16501999
             if let Ok(entries) = std::fs::read_dir(dir) {
16512000
                 for entry in entries.flatten() {
16522001
                     let path = entry.path();
1653
-                    if path.is_dir() { collect(&path, buf); }
1654
-                    else if path.extension().map_or(false, |e| e == "f90") {
2002
+                    if path.is_dir() {
2003
+                        collect(&path, buf);
2004
+                    } else if path.extension().map_or(false, |e| e == "f90") {
16552005
                         if let Ok(src) = std::fs::read_to_string(&path) {
1656
-                            let filtered: String = src.lines()
1657
-                                .map(|l| if l.trim_start().starts_with('#') { "" } else { l })
1658
-                                .collect::<Vec<_>>().join("\n");
2006
+                            let filtered: String = src
2007
+                                .lines()
2008
+                                .map(|l| {
2009
+                                    if l.trim_start().starts_with('#') {
2010
+                                        ""
2011
+                                    } else {
2012
+                                        l
2013
+                                    }
2014
+                                })
2015
+                                .collect::<Vec<_>>()
2016
+                                .join("\n");
16592017
                             buf.push_str(&filtered);
16602018
                             buf.push('\n');
16612019
                         }
@@ -1671,10 +2029,17 @@ end program hello
16712029
 
16722030
         assert!(result.is_ok(), "failed to tokenize: {:?}", result.err());
16732031
         let tokens = result.unwrap();
1674
-        eprintln!("lexed {} tokens from ~{} lines in {:?}",
1675
-            tokens.len(), all_source.lines().count(), elapsed);
1676
-        assert!(elapsed.as_secs_f64() < 1.0,
1677
-            "too slow: {:?} (must be < 1s)", elapsed);
2032
+        eprintln!(
2033
+            "lexed {} tokens from ~{} lines in {:?}",
2034
+            tokens.len(),
2035
+            all_source.lines().count(),
2036
+            elapsed
2037
+        );
2038
+        assert!(
2039
+            elapsed.as_secs_f64() < 1.0,
2040
+            "too slow: {:?} (must be < 1s)",
2041
+            elapsed
2042
+        );
16782043
     }
16792044
 
16802045
     // ======================================================================
@@ -1685,19 +2050,40 @@ end program hello
16852050
     fn continuation_over_comment_line() {
16862051
         // Per F2018 6.3.2.4: comment lines between continued lines are allowed.
16872052
         let k = kinds("x + & \n! this is a comment\n  y");
1688
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
2053
+        assert_eq!(
2054
+            k,
2055
+            vec![
2056
+                TokenKind::Identifier,
2057
+                TokenKind::Plus,
2058
+                TokenKind::Identifier
2059
+            ]
2060
+        );
16892061
     }
16902062
 
16912063
     #[test]
16922064
     fn continuation_over_blank_line() {
16932065
         let k = kinds("x + &\n\n  y");
1694
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
2066
+        assert_eq!(
2067
+            k,
2068
+            vec![
2069
+                TokenKind::Identifier,
2070
+                TokenKind::Plus,
2071
+                TokenKind::Identifier
2072
+            ]
2073
+        );
16952074
     }
16962075
 
16972076
     #[test]
16982077
     fn continuation_over_multiple_comments_and_blanks() {
16992078
         let k = kinds("x + &\n! comment 1\n\n! comment 2\n  y");
1700
-        assert_eq!(k, vec![TokenKind::Identifier, TokenKind::Plus, TokenKind::Identifier]);
2079
+        assert_eq!(
2080
+            k,
2081
+            vec![
2082
+                TokenKind::Identifier,
2083
+                TokenKind::Plus,
2084
+                TokenKind::Identifier
2085
+            ]
2086
+        );
17012087
     }
17022088
 
17032089
     #[test]
@@ -1721,19 +2107,31 @@ end program hello
17212107
         // Round-trip: tokens -> text -> tokens should produce identical kinds.
17222108
         let src = "integer :: x = 42\n";
17232109
         let tokens1 = Lexer::tokenize(src, 0).unwrap();
1724
-        let reconstructed: String = tokens1.iter().map(|t| t.text.as_str()).collect::<Vec<_>>().join(" ");
2110
+        let reconstructed: String = tokens1
2111
+            .iter()
2112
+            .map(|t| t.text.as_str())
2113
+            .collect::<Vec<_>>()
2114
+            .join(" ");
17252115
         let tokens2 = Lexer::tokenize(&reconstructed, 0).unwrap();
17262116
 
17272117
         let kinds1: Vec<_> = tokens1.iter().map(|t| &t.kind).collect();
17282118
         let kinds2: Vec<_> = tokens2.iter().map(|t| &t.kind).collect();
1729
-        assert_eq!(kinds1, kinds2, "round-trip failed:\n  original: {:?}\n  reconstructed: {:?}", src, reconstructed);
2119
+        assert_eq!(
2120
+            kinds1, kinds2,
2121
+            "round-trip failed:\n  original: {:?}\n  reconstructed: {:?}",
2122
+            src, reconstructed
2123
+        );
17302124
     }
17312125
 
17322126
     #[test]
17332127
     fn round_trip_operators() {
17342128
         let src = "x = a + b * c ** d // e\n";
17352129
         let tokens1 = Lexer::tokenize(src, 0).unwrap();
1736
-        let reconstructed: String = tokens1.iter().map(|t| t.text.as_str()).collect::<Vec<_>>().join(" ");
2130
+        let reconstructed: String = tokens1
2131
+            .iter()
2132
+            .map(|t| t.text.as_str())
2133
+            .collect::<Vec<_>>()
2134
+            .join(" ");
17372135
         let tokens2 = Lexer::tokenize(&reconstructed, 0).unwrap();
17382136
 
17392137
         let kinds1: Vec<_> = tokens1.iter().map(|t| &t.kind).collect();
@@ -1751,19 +2149,31 @@ end program hello
17512149
 
17522150
     #[test]
17532151
     fn tokenize_fortsh_types() {
1754
-        let path = concat!(env!("CARGO_MANIFEST_DIR"), "/../fortsh/src/common/types.f90");
2152
+        let path = concat!(
2153
+            env!("CARGO_MANIFEST_DIR"),
2154
+            "/../fortsh/src/common/types.f90"
2155
+        );
17552156
         if !std::path::Path::new(path).exists() {
17562157
             // fortsh not available — skip gracefully.
17572158
             return;
17582159
         }
17592160
         let count = try_lex_fortsh_file(path).unwrap();
1760
-        assert!(count > 100, "expected 100+ tokens from types.f90, got {}", count);
2161
+        assert!(
2162
+            count > 100,
2163
+            "expected 100+ tokens from types.f90, got {}",
2164
+            count
2165
+        );
17612166
     }
17622167
 
17632168
     #[test]
17642169
     fn tokenize_fortsh_error_handling() {
1765
-        let path = concat!(env!("CARGO_MANIFEST_DIR"), "/../fortsh/src/common/error_handling.f90");
1766
-        if !std::path::Path::new(path).exists() { return; }
2170
+        let path = concat!(
2171
+            env!("CARGO_MANIFEST_DIR"),
2172
+            "/../fortsh/src/common/error_handling.f90"
2173
+        );
2174
+        if !std::path::Path::new(path).exists() {
2175
+            return;
2176
+        }
17672177
         let count = try_lex_fortsh_file(path).unwrap();
17682178
         assert!(count > 50, "expected 50+ tokens, got {}", count);
17692179
     }
@@ -1772,7 +2182,9 @@ end program hello
17722182
     fn tokenize_fortsh_all_common() {
17732183
         let common_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../fortsh/src/common");
17742184
         let dir = std::path::Path::new(common_dir);
1775
-        if !dir.exists() { return; }
2185
+        if !dir.exists() {
2186
+            return;
2187
+        }
17762188
 
17772189
         let mut files_tested = 0;
17782190
         let mut total_tokens = 0;
@@ -1791,20 +2203,30 @@ end program hello
17912203
             }
17922204
         }
17932205
         assert!(files_tested > 0, "no .f90 files found in fortsh/src/common");
1794
-        eprintln!("tokenized {} fortsh common/ files, {} total tokens", files_tested, total_tokens);
2206
+        eprintln!(
2207
+            "tokenized {} fortsh common/ files, {} total tokens",
2208
+            files_tested, total_tokens
2209
+        );
17952210
     }
17962211
 
17972212
     #[test]
17982213
     fn tokenize_fortsh_all_sources() {
17992214
         let src_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../fortsh/src");
18002215
         let root = std::path::Path::new(src_dir);
1801
-        if !root.exists() { return; }
2216
+        if !root.exists() {
2217
+            return;
2218
+        }
18022219
 
18032220
         let mut files_tested = 0;
18042221
         let mut total_tokens = 0;
18052222
         let mut failures = Vec::new();
18062223
 
1807
-        fn visit_dir(dir: &std::path::Path, files_tested: &mut usize, total_tokens: &mut usize, failures: &mut Vec<String>) {
2224
+        fn visit_dir(
2225
+            dir: &std::path::Path,
2226
+            files_tested: &mut usize,
2227
+            total_tokens: &mut usize,
2228
+            failures: &mut Vec<String>,
2229
+        ) {
18082230
             if let Ok(entries) = std::fs::read_dir(dir) {
18092231
                 for entry in entries.flatten() {
18102232
                     let path = entry.path();
@@ -1827,11 +2249,22 @@ end program hello
18272249
         visit_dir(root, &mut files_tested, &mut total_tokens, &mut failures);
18282250
 
18292251
         if !failures.is_empty() {
1830
-            panic!("{} of {} files failed to tokenize:\n{}", failures.len(), files_tested + failures.len(),
1831
-                failures.join("\n"));
2252
+            panic!(
2253
+                "{} of {} files failed to tokenize:\n{}",
2254
+                failures.len(),
2255
+                files_tested + failures.len(),
2256
+                failures.join("\n")
2257
+            );
18322258
         }
18332259
 
1834
-        assert!(files_tested > 40, "expected 40+ .f90 files, found {}", files_tested);
1835
-        eprintln!("tokenized ALL {} fortsh .f90 files, {} total tokens", files_tested, total_tokens);
2260
+        assert!(
2261
+            files_tested > 40,
2262
+            "expected 40+ .f90 files, found {}",
2263
+            files_tested
2264
+        );
2265
+        eprintln!(
2266
+            "tokenized ALL {} fortsh .f90 files, {} total tokens",
2267
+            files_tested, total_tokens
2268
+        );
18362269
     }
18372270
 }
src/opt/alias.rsmodified
276 lines changed — click to load
@@ -13,9 +13,9 @@
1313
 //! Used by GVN (to determine if a store kills a prior load's value)
1414
 //! cross-block load-store forwarding, and LICM load hoisting.
1515
 
16
+use super::loop_utils::resolve_const_int;
1617
 use crate::ir::inst::*;
1718
 use crate::ir::types::IrType;
18
-use super::loop_utils::resolve_const_int;
1919
 
2020
 /// Result of an alias query between two pointer values.
2121
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -71,7 +71,9 @@ pub fn may_reach_through_call_arg(func: &Function, entry_ptr: ValueId, call_arg:
7171
 /// GlobalAddr, GetElementPtr, or function parameters).
7272
 pub fn query(func: &Function, a: ValueId, b: ValueId) -> AliasResult {
7373
     // Same value → must alias.
74
-    if a == b { return AliasResult::MustAlias; }
74
+    if a == b {
75
+        return AliasResult::MustAlias;
76
+    }
7577
 
7678
     // Trace both pointers to their base + offset.
7779
     let base_a = trace_base(func, a);
@@ -80,10 +82,14 @@ pub fn query(func: &Function, a: ValueId, b: ValueId) -> AliasResult {
8082
     // Different base pointers → no alias (Fortran guarantee).
8183
     match (&base_a, &base_b) {
8284
         (PtrBase::Alloca(id_a), PtrBase::Alloca(id_b)) => {
83
-            if id_a != id_b { return AliasResult::NoAlias; }
85
+            if id_a != id_b {
86
+                return AliasResult::NoAlias;
87
+            }
8488
         }
8589
         (PtrBase::Global(name_a), PtrBase::Global(name_b)) => {
86
-            if name_a != name_b { return AliasResult::NoAlias; }
90
+            if name_a != name_b {
91
+                return AliasResult::NoAlias;
92
+            }
8793
         }
8894
         (PtrBase::Param(id_a), PtrBase::Param(id_b)) => {
8995
             if id_a != id_b
@@ -93,10 +99,10 @@ pub fn query(func: &Function, a: ValueId, b: ValueId) -> AliasResult {
9399
                 return AliasResult::NoAlias;
94100
             }
95101
         }
96
-        (PtrBase::Alloca(_), PtrBase::Global(_)) |
97
-        (PtrBase::Global(_), PtrBase::Alloca(_)) |
98
-        (PtrBase::Alloca(_), PtrBase::Param(_)) |
99
-        (PtrBase::Param(_), PtrBase::Alloca(_)) => {
102
+        (PtrBase::Alloca(_), PtrBase::Global(_))
103
+        | (PtrBase::Global(_), PtrBase::Alloca(_))
104
+        | (PtrBase::Alloca(_), PtrBase::Param(_))
105
+        | (PtrBase::Param(_), PtrBase::Alloca(_)) => {
100106
             return AliasResult::NoAlias;
101107
         }
102108
         _ => {}
@@ -150,7 +156,9 @@ impl PtrBase {
150156
 fn trace_base(func: &Function, ptr: ValueId) -> PtrBase {
151157
     // Check if this is a function parameter (pointer arg).
152158
     for param in &func.params {
153
-        if param.id == ptr { return PtrBase::Param(ptr); }
159
+        if param.id == ptr {
160
+            return PtrBase::Param(ptr);
161
+        }
154162
     }
155163
 
156164
     // Find the defining instruction.
@@ -180,7 +188,9 @@ fn trace_offset(func: &Function, ptr: ValueId) -> Option<i64> {
180188
         InstKind::Load(addr) => trace_param_wrapper(func, *addr).map(|_| 0),
181189
         InstKind::GetElementPtr(base, indices) => {
182190
             let base_offset = trace_offset(func, *base)?;
183
-            if indices.len() != 1 { return None; }
191
+            if indices.len() != 1 {
192
+                return None;
193
+            }
184194
             let idx = resolve_const_int(func, indices[0])?;
185195
             let step = match &inst.ty {
186196
                 IrType::Ptr(inner) => inner.size_bytes() as i64,
@@ -236,7 +246,9 @@ fn trace_param_wrapper(func: &Function, addr: ValueId) -> Option<ValueId> {
236246
 fn find_inst(func: &Function, vid: ValueId) -> Option<&Inst> {
237247
     for block in &func.blocks {
238248
         for inst in &block.insts {
239
-            if inst.id == vid { return Some(inst); }
249
+            if inst.id == vid {
250
+                return Some(inst);
251
+            }
240252
         }
241253
     }
242254
     None
@@ -249,12 +261,16 @@ fn find_inst(func: &Function, vid: ValueId) -> Option<&Inst> {
249261
 #[cfg(test)]
250262
 mod tests {
251263
     use super::*;
252
-    use crate::ir::types::{IrType, IntWidth};
253
-    use crate::lexer::{Span, Position};
264
+    use crate::ir::types::{IntWidth, IrType};
265
+    use crate::lexer::{Position, Span};
254266
 
255267
     fn span() -> Span {
256268
         let pos = Position { line: 0, col: 0 };
257
-        Span { file_id: 0, start: pos, end: pos }
269
+        Span {
270
+            file_id: 0,
271
+            start: pos,
272
+            end: pos,
273
+        }
258274
     }
259275
 
260276
     fn param(name: &str, id: u32, ty: IrType, fortran_noalias: bool) -> Param {
@@ -272,13 +288,17 @@ mod tests {
272288
         let a = f.next_value_id();
273289
         f.register_type(a, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
274290
         f.block_mut(f.entry).insts.push(Inst {
275
-            id: a, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
291
+            id: a,
292
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
293
+            span: span(),
276294
             kind: InstKind::Alloca(IrType::Int(IntWidth::I32)),
277295
         });
278296
         let b = f.next_value_id();
279297
         f.register_type(b, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
280298
         f.block_mut(f.entry).insts.push(Inst {
281
-            id: b, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
299
+            id: b,
300
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
301
+            span: span(),
282302
             kind: InstKind::Alloca(IrType::Int(IntWidth::I32)),
283303
         });
284304
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -292,7 +312,9 @@ mod tests {
292312
         let a = f.next_value_id();
293313
         f.register_type(a, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
294314
         f.block_mut(f.entry).insts.push(Inst {
295
-            id: a, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
315
+            id: a,
316
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
317
+            span: span(),
296318
             kind: InstKind::Alloca(IrType::Int(IntWidth::I32)),
297319
         });
298320
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -351,33 +373,43 @@ mod tests {
351373
         let base = f.next_value_id();
352374
         f.register_type(base, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
353375
         f.block_mut(f.entry).insts.push(Inst {
354
-            id: base, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
376
+            id: base,
377
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
378
+            span: span(),
355379
             kind: InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 10)),
356380
         });
357381
         // GEP at offset 0
358382
         let c0 = f.next_value_id();
359383
         f.register_type(c0, IrType::Int(IntWidth::I64));
360384
         f.block_mut(f.entry).insts.push(Inst {
361
-            id: c0, ty: IrType::Int(IntWidth::I64), span: span(),
385
+            id: c0,
386
+            ty: IrType::Int(IntWidth::I64),
387
+            span: span(),
362388
             kind: InstKind::ConstInt(0, IntWidth::I64),
363389
         });
364390
         let gep0 = f.next_value_id();
365391
         f.register_type(gep0, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
366392
         f.block_mut(f.entry).insts.push(Inst {
367
-            id: gep0, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
393
+            id: gep0,
394
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
395
+            span: span(),
368396
             kind: InstKind::GetElementPtr(base, vec![c0]),
369397
         });
370398
         // GEP at offset 1
371399
         let c1 = f.next_value_id();
372400
         f.register_type(c1, IrType::Int(IntWidth::I64));
373401
         f.block_mut(f.entry).insts.push(Inst {
374
-            id: c1, ty: IrType::Int(IntWidth::I64), span: span(),
402
+            id: c1,
403
+            ty: IrType::Int(IntWidth::I64),
404
+            span: span(),
375405
             kind: InstKind::ConstInt(1, IntWidth::I64),
376406
         });
377407
         let gep1 = f.next_value_id();
378408
         f.register_type(gep1, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
379409
         f.block_mut(f.entry).insts.push(Inst {
380
-            id: gep1, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
410
+            id: gep1,
411
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
412
+            span: span(),
381413
             kind: InstKind::GetElementPtr(base, vec![c1]),
382414
         });
383415
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -389,10 +421,19 @@ mod tests {
389421
     fn aggregate_base_and_element_gep_may_alias() {
390422
         let mut f = Function::new("test".into(), vec![], IrType::Void);
391423
         let base = f.next_value_id();
392
-        f.register_type(base, IrType::Ptr(Box::new(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 10))));
424
+        f.register_type(
425
+            base,
426
+            IrType::Ptr(Box::new(IrType::Array(
427
+                Box::new(IrType::Int(IntWidth::I32)),
428
+                10,
429
+            ))),
430
+        );
393431
         f.block_mut(f.entry).insts.push(Inst {
394432
             id: base,
395
-            ty: IrType::Ptr(Box::new(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 10))),
433
+            ty: IrType::Ptr(Box::new(IrType::Array(
434
+                Box::new(IrType::Int(IntWidth::I32)),
435
+                10,
436
+            ))),
396437
             span: span(),
397438
             kind: InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 10)),
398439
         });
@@ -425,13 +466,17 @@ mod tests {
425466
         let ga = f.next_value_id();
426467
         f.register_type(ga, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
427468
         f.block_mut(f.entry).insts.push(Inst {
428
-            id: ga, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
469
+            id: ga,
470
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
471
+            span: span(),
429472
             kind: InstKind::GlobalAddr("array_a".into()),
430473
         });
431474
         let gb = f.next_value_id();
432475
         f.register_type(gb, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
433476
         f.block_mut(f.entry).insts.push(Inst {
434
-            id: gb, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
477
+            id: gb,
478
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
479
+            span: span(),
435480
             kind: InstKind::GlobalAddr("array_b".into()),
436481
         });
437482
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -442,8 +487,18 @@ mod tests {
442487
     #[test]
443488
     fn distinct_noalias_params_do_not_alias() {
444489
         let params = vec![
445
-            param("a", 0, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), true),
446
-            param("b", 1, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), true),
490
+            param(
491
+                "a",
492
+                0,
493
+                IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
494
+                true,
495
+            ),
496
+            param(
497
+                "b",
498
+                1,
499
+                IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
500
+                true,
501
+            ),
447502
         ];
448503
         let mut f = Function::new("test".into(), params, IrType::Void);
449504
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -454,13 +509,26 @@ mod tests {
454509
     #[test]
455510
     fn wrapper_loads_trace_back_to_noalias_params() {
456511
         let params = vec![
457
-            param("a", 0, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), true),
458
-            param("b", 1, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), true),
512
+            param(
513
+                "a",
514
+                0,
515
+                IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
516
+                true,
517
+            ),
518
+            param(
519
+                "b",
520
+                1,
521
+                IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
522
+                true,
523
+            ),
459524
         ];
460525
         let mut f = Function::new("test".into(), params, IrType::Void);
461526
 
462527
         let slot_a = f.next_value_id();
463
-        f.register_type(slot_a, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))));
528
+        f.register_type(
529
+            slot_a,
530
+            IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
531
+        );
464532
         f.block_mut(f.entry).insts.push(Inst {
465533
             id: slot_a,
466534
             ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
@@ -468,7 +536,10 @@ mod tests {
468536
             kind: InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
469537
         });
470538
         let slot_b = f.next_value_id();
471
-        f.register_type(slot_b, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))));
539
+        f.register_type(
540
+            slot_b,
541
+            IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
542
+        );
472543
         f.block_mut(f.entry).insts.push(Inst {
473544
             id: slot_b,
474545
             ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
src/opt/audit_tests.rsmodified
1717 lines changed — click to load
@@ -6,26 +6,35 @@
66
 
77
 #![cfg(test)]
88
 
9
-use crate::ir::inst::*;
10
-use crate::ir::types::{IrType, IntWidth, FloatWidth};
11
-use crate::lexer::{Span, Position};
12
-use crate::ir::verify::verify_module;
13
-use super::pass::Pass;
149
 use super::const_fold::ConstFold;
1510
 use super::const_prop::ConstProp;
1611
 use super::dce::Dce;
17
-use super::strength_reduce::StrengthReduce;
1812
 use super::licm::Licm;
13
+use super::pass::Pass;
14
+use super::strength_reduce::StrengthReduce;
15
+use crate::ir::inst::*;
16
+use crate::ir::types::{FloatWidth, IntWidth, IrType};
17
+use crate::ir::verify::verify_module;
18
+use crate::lexer::{Position, Span};
1919
 
2020
 fn dummy_span() -> Span {
2121
     let p = Position { line: 1, col: 1 };
22
-    Span { start: p, end: p, file_id: 0 }
22
+    Span {
23
+        start: p,
24
+        end: p,
25
+        file_id: 0,
26
+    }
2327
 }
2428
 
2529
 fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
2630
     let id = f.next_value_id();
2731
     let entry = f.entry;
28
-    f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
32
+    f.block_mut(entry).insts.push(Inst {
33
+        id,
34
+        kind,
35
+        ty,
36
+        span: dummy_span(),
37
+    });
2938
     id
3039
 }
3140
 
@@ -41,18 +50,33 @@ fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
4150
 fn audit_const_fold_int_to_f32_must_round() {
4251
     let mut m = Module::new("t".into());
4352
     let mut f = Function::new("f".into(), vec![], IrType::Float(FloatWidth::F32));
44
-    let i = push(&mut f, InstKind::ConstInt(16_777_217, IntWidth::I32), IrType::Int(IntWidth::I32));
45
-    let cv = push(&mut f, InstKind::IntToFloat(i, FloatWidth::F32), IrType::Float(FloatWidth::F32));
53
+    let i = push(
54
+        &mut f,
55
+        InstKind::ConstInt(16_777_217, IntWidth::I32),
56
+        IrType::Int(IntWidth::I32),
57
+    );
58
+    let cv = push(
59
+        &mut f,
60
+        InstKind::IntToFloat(i, FloatWidth::F32),
61
+        IrType::Float(FloatWidth::F32),
62
+    );
4663
     let entry = f.entry;
4764
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(cv)));
4865
     m.add_function(f);
4966
 
5067
     ConstFold.run(&mut m);
51
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == cv).unwrap();
68
+    let folded = m.functions[0].blocks[0]
69
+        .insts
70
+        .iter()
71
+        .find(|i| i.id == cv)
72
+        .unwrap();
5273
     match folded.kind {
5374
         InstKind::ConstFloat(v, FloatWidth::F32) => {
54
-            assert_eq!(v, 16_777_216.0,
55
-                "expected f32-precision result 16_777_216.0, got {}", v);
75
+            assert_eq!(
76
+                v, 16_777_216.0,
77
+                "expected f32-precision result 16_777_216.0, got {}",
78
+                v
79
+            );
5680
         }
5781
         ref other => panic!("expected ConstFloat, got {:?}", other),
5882
     }
@@ -67,14 +91,26 @@ fn audit_const_fold_int_to_f32_must_round() {
6791
 fn audit_const_fold_float_trunc_must_round() {
6892
     let mut m = Module::new("t".into());
6993
     let mut f = Function::new("f".into(), vec![], IrType::Float(FloatWidth::F32));
70
-    let d = push(&mut f, InstKind::ConstFloat(16_777_217.0, FloatWidth::F64), IrType::Float(FloatWidth::F64));
71
-    let cv = push(&mut f, InstKind::FloatTrunc(d, FloatWidth::F32), IrType::Float(FloatWidth::F32));
94
+    let d = push(
95
+        &mut f,
96
+        InstKind::ConstFloat(16_777_217.0, FloatWidth::F64),
97
+        IrType::Float(FloatWidth::F64),
98
+    );
99
+    let cv = push(
100
+        &mut f,
101
+        InstKind::FloatTrunc(d, FloatWidth::F32),
102
+        IrType::Float(FloatWidth::F32),
103
+    );
72104
     let entry = f.entry;
73105
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(cv)));
74106
     m.add_function(f);
75107
 
76108
     ConstFold.run(&mut m);
77
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == cv).unwrap();
109
+    let folded = m.functions[0].blocks[0]
110
+        .insts
111
+        .iter()
112
+        .find(|i| i.id == cv)
113
+        .unwrap();
78114
     match folded.kind {
79115
         InstKind::ConstFloat(v, FloatWidth::F32) => {
80116
             assert_eq!(v, 16_777_216.0, "expected f32-rounded value, got {}", v);
@@ -93,13 +129,37 @@ fn audit_const_fold_float_trunc_must_round() {
93129
 fn audit_strength_reduce_chained_identities() {
94130
     let mut m = Module::new("t".into());
95131
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
96
-    let x  = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
97
-    let one1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
132
+    let x = push(
133
+        &mut f,
134
+        InstKind::ConstInt(7, IntWidth::I32),
135
+        IrType::Int(IntWidth::I32),
136
+    );
137
+    let one1 = push(
138
+        &mut f,
139
+        InstKind::ConstInt(1, IntWidth::I32),
140
+        IrType::Int(IntWidth::I32),
141
+    );
98142
     let mul1 = push(&mut f, InstKind::IMul(x, one1), IrType::Int(IntWidth::I32));
99
-    let one2 = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
100
-    let mul2 = push(&mut f, InstKind::IMul(mul1, one2), IrType::Int(IntWidth::I32));
101
-    let zero = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
102
-    let add  = push(&mut f, InstKind::IAdd(mul2, zero), IrType::Int(IntWidth::I32));
143
+    let one2 = push(
144
+        &mut f,
145
+        InstKind::ConstInt(1, IntWidth::I32),
146
+        IrType::Int(IntWidth::I32),
147
+    );
148
+    let mul2 = push(
149
+        &mut f,
150
+        InstKind::IMul(mul1, one2),
151
+        IrType::Int(IntWidth::I32),
152
+    );
153
+    let zero = push(
154
+        &mut f,
155
+        InstKind::ConstInt(0, IntWidth::I32),
156
+        IrType::Int(IntWidth::I32),
157
+    );
158
+    let add = push(
159
+        &mut f,
160
+        InstKind::IAdd(mul2, zero),
161
+        IrType::Int(IntWidth::I32),
162
+    );
103163
     let entry = f.entry;
104164
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(add)));
105165
     m.add_function(f);
@@ -108,13 +168,18 @@ fn audit_strength_reduce_chained_identities() {
108168
     // After three chained identities, the return must reference x.
109169
     let term = m.functions[0].blocks[0].terminator.as_ref().unwrap();
110170
     match term {
111
-        Terminator::Return(Some(v)) => assert_eq!(*v, x,
112
-            "expected return %{} (x), got %{}", x.0, v.0),
171
+        Terminator::Return(Some(v)) => {
172
+            assert_eq!(*v, x, "expected return %{} (x), got %{}", x.0, v.0)
173
+        }
113174
         other => panic!("expected Return(x), got {:?}", other),
114175
     }
115176
     // And the IR must still verify.
116177
     let errs = verify_module(&m);
117
-    assert!(errs.is_empty(), "verifier errors after chained rewrites: {:?}", errs);
178
+    assert!(
179
+        errs.is_empty(),
180
+        "verifier errors after chained rewrites: {:?}",
181
+        errs
182
+    );
118183
 }
119184
 
120185
 // =============================================================
@@ -131,11 +196,27 @@ fn audit_strength_reduce_mixed_shl_and_identity_in_block() {
131196
     // ret %4
132197
     let mut m = Module::new("t".into());
133198
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
134
-    let x = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
135
-    let eight = push(&mut f, InstKind::ConstInt(8, IntWidth::I32), IrType::Int(IntWidth::I32));
199
+    let x = push(
200
+        &mut f,
201
+        InstKind::ConstInt(7, IntWidth::I32),
202
+        IrType::Int(IntWidth::I32),
203
+    );
204
+    let eight = push(
205
+        &mut f,
206
+        InstKind::ConstInt(8, IntWidth::I32),
207
+        IrType::Int(IntWidth::I32),
208
+    );
136209
     let mul1 = push(&mut f, InstKind::IMul(x, eight), IrType::Int(IntWidth::I32));
137
-    let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
138
-    let mul2 = push(&mut f, InstKind::IMul(mul1, one), IrType::Int(IntWidth::I32));
210
+    let one = push(
211
+        &mut f,
212
+        InstKind::ConstInt(1, IntWidth::I32),
213
+        IrType::Int(IntWidth::I32),
214
+    );
215
+    let mul2 = push(
216
+        &mut f,
217
+        InstKind::IMul(mul1, one),
218
+        IrType::Int(IntWidth::I32),
219
+    );
139220
     let entry = f.entry;
140221
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(mul2)));
141222
     m.add_function(f);
@@ -151,8 +232,11 @@ fn audit_strength_reduce_mixed_shl_and_identity_in_block() {
151232
         _ => panic!(),
152233
     };
153234
     let term_kind = &block.insts.iter().find(|i| i.id == term_val).unwrap().kind;
154
-    assert!(matches!(term_kind, InstKind::Shl(..)),
155
-        "expected return value to define a Shl, got {:?}", term_kind);
235
+    assert!(
236
+        matches!(term_kind, InstKind::Shl(..)),
237
+        "expected return value to define a Shl, got {:?}",
238
+        term_kind
239
+    );
156240
 }
157241
 
158242
 // =============================================================
@@ -165,20 +249,33 @@ fn audit_strength_reduce_mixed_shl_and_identity_in_block() {
165249
 fn audit_const_fold_idiv_i8_min_neg_one() {
166250
     let mut m = Module::new("t".into());
167251
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I8));
168
-    let a = push(&mut f, InstKind::ConstInt(-128, IntWidth::I8), IrType::Int(IntWidth::I8));
169
-    let b = push(&mut f, InstKind::ConstInt(-1, IntWidth::I8), IrType::Int(IntWidth::I8));
252
+    let a = push(
253
+        &mut f,
254
+        InstKind::ConstInt(-128, IntWidth::I8),
255
+        IrType::Int(IntWidth::I8),
256
+    );
257
+    let b = push(
258
+        &mut f,
259
+        InstKind::ConstInt(-1, IntWidth::I8),
260
+        IrType::Int(IntWidth::I8),
261
+    );
170262
     let q = push(&mut f, InstKind::IDiv(a, b), IrType::Int(IntWidth::I8));
171263
     let entry = f.entry;
172264
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(q)));
173265
     m.add_function(f);
174266
 
175267
     ConstFold.run(&mut m);
176
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == q).unwrap();
268
+    let folded = m.functions[0].blocks[0]
269
+        .insts
270
+        .iter()
271
+        .find(|i| i.id == q)
272
+        .unwrap();
177273
     // Either we fold to -128 (match hardware), or we leave the IDiv alone.
178274
     // Anything else would be a divergence.
179275
     match folded.kind {
180
-        InstKind::ConstInt(v, IntWidth::I8) => assert_eq!(v, -128,
181
-            "expected -128 (i8 wraparound), got {}", v),
276
+        InstKind::ConstInt(v, IntWidth::I8) => {
277
+            assert_eq!(v, -128, "expected -128 (i8 wraparound), got {}", v)
278
+        }
182279
         InstKind::IDiv(..) => { /* left alone, also acceptable */ }
183280
         ref other => panic!("unexpected fold: {:?}", other),
184281
     }
@@ -198,7 +295,11 @@ fn audit_dce_removes_dead_block_param() {
198295
         id: param_id,
199296
         ty: IrType::Int(IntWidth::I32),
200297
     });
201
-    let init = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
298
+    let init = push(
299
+        &mut f,
300
+        InstKind::ConstInt(0, IntWidth::I32),
301
+        IrType::Int(IntWidth::I32),
302
+    );
202303
     let entry = f.entry;
203304
     f.block_mut(entry).terminator = Some(Terminator::Branch(target, vec![init]));
204305
     f.block_mut(target).terminator = Some(Terminator::Return(None));
@@ -206,19 +307,31 @@ fn audit_dce_removes_dead_block_param() {
206307
 
207308
     assert!(Dce.run(&mut m), "DCE should report change");
208309
     let f = &m.functions[0];
209
-    assert_eq!(f.block(target).params.len(), 0, "dead block param must be removed");
310
+    assert_eq!(
311
+        f.block(target).params.len(),
312
+        0,
313
+        "dead block param must be removed"
314
+    );
210315
     // The predecessor's branch arg list must shrink in lockstep.
211316
     let entry_term = f.block(f.entry).terminator.as_ref().unwrap();
212317
     match entry_term {
213
-        Terminator::Branch(_, args) => assert_eq!(args.len(), 0,
214
-            "predecessor branch arg must be dropped alongside the dead param"),
318
+        Terminator::Branch(_, args) => assert_eq!(
319
+            args.len(),
320
+            0,
321
+            "predecessor branch arg must be dropped alongside the dead param"
322
+        ),
215323
         _ => panic!(),
216324
     }
217325
     // The const(0) inst is now unreferenced and should also be DCE'd.
218
-    let const_remains = f.blocks.iter()
326
+    let const_remains = f
327
+        .blocks
328
+        .iter()
219329
         .flat_map(|b| b.insts.iter())
220330
         .any(|i| matches!(i.kind, InstKind::ConstInt(0, _)));
221
-    assert!(!const_remains, "const(0) should also be DCE'd after its only use disappears");
331
+    assert!(
332
+        !const_remains,
333
+        "const(0) should also be DCE'd after its only use disappears"
334
+    );
222335
 }
223336
 
224337
 #[test]
@@ -232,7 +345,11 @@ fn audit_dce_keeps_live_block_param() {
232345
         id: param_id,
233346
         ty: IrType::Int(IntWidth::I32),
234347
     });
235
-    let init = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
348
+    let init = push(
349
+        &mut f,
350
+        InstKind::ConstInt(7, IntWidth::I32),
351
+        IrType::Int(IntWidth::I32),
352
+    );
236353
     let entry = f.entry;
237354
     f.block_mut(entry).terminator = Some(Terminator::Branch(target, vec![init]));
238355
     f.block_mut(target).terminator = Some(Terminator::Return(Some(param_id)));
@@ -240,7 +357,11 @@ fn audit_dce_keeps_live_block_param() {
240357
 
241358
     Dce.run(&mut m);
242359
     let f = &m.functions[0];
243
-    assert_eq!(f.block(target).params.len(), 1, "live block param must survive");
360
+    assert_eq!(
361
+        f.block(target).params.len(),
362
+        1,
363
+        "live block param must survive"
364
+    );
244365
 }
245366
 
246367
 #[test]
@@ -254,10 +375,24 @@ fn audit_dce_removes_one_of_two_block_params_keeps_correct_arg() {
254375
     let target = f.create_block("target");
255376
     let p0 = f.next_value_id();
256377
     let p1 = f.next_value_id();
257
-    f.block_mut(target).params.push(BlockParam { id: p0, ty: IrType::Int(IntWidth::I32) });
258
-    f.block_mut(target).params.push(BlockParam { id: p1, ty: IrType::Int(IntWidth::I32) });
259
-    let c0 = push(&mut f, InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32));
260
-    let c1 = push(&mut f, InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32));
378
+    f.block_mut(target).params.push(BlockParam {
379
+        id: p0,
380
+        ty: IrType::Int(IntWidth::I32),
381
+    });
382
+    f.block_mut(target).params.push(BlockParam {
383
+        id: p1,
384
+        ty: IrType::Int(IntWidth::I32),
385
+    });
386
+    let c0 = push(
387
+        &mut f,
388
+        InstKind::ConstInt(10, IntWidth::I32),
389
+        IrType::Int(IntWidth::I32),
390
+    );
391
+    let c1 = push(
392
+        &mut f,
393
+        InstKind::ConstInt(20, IntWidth::I32),
394
+        IrType::Int(IntWidth::I32),
395
+    );
261396
     let entry = f.entry;
262397
     f.block_mut(entry).terminator = Some(Terminator::Branch(target, vec![c0, c1]));
263398
     f.block_mut(target).terminator = Some(Terminator::Return(Some(p1)));
@@ -281,10 +416,15 @@ fn audit_dce_removes_one_of_two_block_params_keeps_correct_arg() {
281416
 
282417
     // Now const(10) is dead — should also be gone after the
283418
     // outer-loop re-runs the inner DCE.
284
-    let c0_remains = f.blocks.iter()
419
+    let c0_remains = f
420
+        .blocks
421
+        .iter()
285422
         .flat_map(|b| b.insts.iter())
286423
         .any(|i| i.id == c0);
287
-    assert!(!c0_remains, "const(10) should be DCE'd after its arg slot is gone");
424
+    assert!(
425
+        !c0_remains,
426
+        "const(10) should be DCE'd after its arg slot is gone"
427
+    );
288428
 }
289429
 
290430
 // =============================================================
@@ -324,25 +464,33 @@ fn audit_dce_cascading_across_outer_iterations() {
324464
     let mut f = Function::new("f".into(), vec![], IrType::Void);
325465
 
326466
     // entry: computes %c, branches to other
327
-    let c = push(&mut f, InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32));
467
+    let c = push(
468
+        &mut f,
469
+        InstKind::ConstInt(5, IntWidth::I32),
470
+        IrType::Int(IntWidth::I32),
471
+    );
328472
 
329473
     // other: has param p_other, computes %u = ineg p_other, branches to target
330474
     let other = f.create_block("other");
331475
     let p_other = f.next_value_id();
332476
     f.block_mut(other).params.push(BlockParam {
333
-        id: p_other, ty: IrType::Int(IntWidth::I32),
477
+        id: p_other,
478
+        ty: IrType::Int(IntWidth::I32),
334479
     });
335480
     let u = f.next_value_id();
336481
     f.block_mut(other).insts.push(Inst {
337
-        id: u, kind: InstKind::INeg(p_other),
338
-        ty: IrType::Int(IntWidth::I32), span: dummy_span(),
482
+        id: u,
483
+        kind: InstKind::INeg(p_other),
484
+        ty: IrType::Int(IntWidth::I32),
485
+        span: dummy_span(),
339486
     });
340487
 
341488
     // target: has param p_target, returns (p_target never used).
342489
     let target = f.create_block("target");
343490
     let p_target = f.next_value_id();
344491
     f.block_mut(target).params.push(BlockParam {
345
-        id: p_target, ty: IrType::Int(IntWidth::I32),
492
+        id: p_target,
493
+        ty: IrType::Int(IntWidth::I32),
346494
     });
347495
     f.block_mut(target).terminator = Some(Terminator::Return(None));
348496
 
@@ -357,30 +505,46 @@ fn audit_dce_cascading_across_outer_iterations() {
357505
     let f = &m.functions[0];
358506
 
359507
     // Both block params must be gone.
360
-    assert_eq!(f.block(target).params.len(), 0,
361
-        "p_target should be removed in round 1");
362
-    assert_eq!(f.block(other).params.len(), 0,
363
-        "p_other should be removed in round 2 (cascading)");
508
+    assert_eq!(
509
+        f.block(target).params.len(),
510
+        0,
511
+        "p_target should be removed in round 1"
512
+    );
513
+    assert_eq!(
514
+        f.block(other).params.len(),
515
+        0,
516
+        "p_other should be removed in round 2 (cascading)"
517
+    );
364518
 
365519
     // Entry's branch arg list must be empty.
366520
     match f.block(f.entry).terminator.as_ref().unwrap() {
367
-        Terminator::Branch(_, args) => assert_eq!(args.len(), 0,
368
-            "entry's branch to other should have no args after cascade"),
521
+        Terminator::Branch(_, args) => assert_eq!(
522
+            args.len(),
523
+            0,
524
+            "entry's branch to other should have no args after cascade"
525
+        ),
369526
         _ => panic!(),
370527
     }
371528
     // other's branch to target must also have no args.
372529
     match f.block(other).terminator.as_ref().unwrap() {
373
-        Terminator::Branch(_, args) => assert_eq!(args.len(), 0,
374
-            "other's branch to target should have no args"),
530
+        Terminator::Branch(_, args) => assert_eq!(
531
+            args.len(),
532
+            0,
533
+            "other's branch to target should have no args"
534
+        ),
375535
         _ => panic!(),
376536
     }
377537
 
378538
     // All formerly-live values should be DCE'd: %c, %u.
379
-    let any_inst = f.blocks.iter()
539
+    let any_inst = f
540
+        .blocks
541
+        .iter()
380542
         .flat_map(|b| b.insts.iter())
381543
         .any(|i| i.id == c || i.id == u);
382
-    assert!(!any_inst,
383
-        "dead instructions %c (const) and %u (ineg) should be DCE'd after the cascade");
544
+    assert!(
545
+        !any_inst,
546
+        "dead instructions %c (const) and %u (ineg) should be DCE'd after the cascade"
547
+    );
384548
 }
385549
 
386550
 // =============================================================
@@ -471,26 +635,45 @@ fn audit_licm_nested_loop_body_computation() {
471635
     assert_eq!(loops.len(), 2, "expected exactly two natural loops");
472636
 
473637
     // Find the inner and outer loops by their headers.
474
-    let inner = loops.iter().find(|l| l.header == inner_header).expect("inner loop not found");
475
-    let outer = loops.iter().find(|l| l.header == outer_header).expect("outer loop not found");
638
+    let inner = loops
639
+        .iter()
640
+        .find(|l| l.header == inner_header)
641
+        .expect("inner loop not found");
642
+    let outer = loops
643
+        .iter()
644
+        .find(|l| l.header == outer_header)
645
+        .expect("outer loop not found");
476646
 
477647
     // Inner loop body: {inner_header, inner_latch}.
478
-    assert_eq!(inner.body.len(), 2,
479
-        "inner body should be {{inner_header, inner_latch}}, got {:?}", inner.body);
648
+    assert_eq!(
649
+        inner.body.len(),
650
+        2,
651
+        "inner body should be {{inner_header, inner_latch}}, got {:?}",
652
+        inner.body
653
+    );
480654
     assert!(inner.body.contains(&inner_header));
481655
     assert!(inner.body.contains(&inner_latch));
482656
 
483657
     // Outer loop body: {outer_header, inner_header, inner_latch, outer_latch}.
484658
     // MUST NOT contain entry or exit.
485
-    assert_eq!(outer.body.len(), 4,
659
+    assert_eq!(
660
+        outer.body.len(),
661
+        4,
486662
         "outer body should be {{outer_header, inner_header, inner_latch, outer_latch}}, got {:?}",
487
-        outer.body);
663
+        outer.body
664
+    );
488665
     assert!(outer.body.contains(&outer_header));
489666
     assert!(outer.body.contains(&inner_header));
490667
     assert!(outer.body.contains(&inner_latch));
491668
     assert!(outer.body.contains(&outer_latch));
492
-    assert!(!outer.body.contains(&entry), "outer body must not include entry");
493
-    assert!(!outer.body.contains(&exit), "outer body must not include exit");
669
+    assert!(
670
+        !outer.body.contains(&entry),
671
+        "outer body must not include entry"
672
+    );
673
+    assert!(
674
+        !outer.body.contains(&exit),
675
+        "outer body must not include exit"
676
+    );
494677
 }
495678
 
496679
 // =============================================================
@@ -560,9 +743,15 @@ fn audit_licm_multi_latch_with_self_loop() {
560743
     assert_eq!(lp.header, header);
561744
     // Body must include header and other, NOT entry.
562745
     assert!(lp.body.contains(&header), "body must include header");
563
-    assert!(lp.body.contains(&other),  "body must include other");
564
-    assert!(!lp.body.contains(&entry), "body must NOT include the preheader (entry)");
565
-    assert!(!lp.body.contains(&exit),  "body must NOT include the exit block");
746
+    assert!(lp.body.contains(&other), "body must include other");
747
+    assert!(
748
+        !lp.body.contains(&entry),
749
+        "body must NOT include the preheader (entry)"
750
+    );
751
+    assert!(
752
+        !lp.body.contains(&exit),
753
+        "body must NOT include the exit block"
754
+    );
566755
     // Latches: both header (self-loop) and other (back edge).
567756
     assert_eq!(lp.latches.len(), 2, "expected two latches");
568757
     assert!(lp.latches.contains(&header));
@@ -581,15 +770,24 @@ fn audit_licm_multi_latch_with_self_loop() {
581770
 fn audit_licm_hoists_clean_alloca_load() {
582771
     let mut m = Module::new("t".into());
583772
     let mut f = Function::new("f".into(), vec![], IrType::Void);
584
-    let slot = push(&mut f,
773
+    let slot = push(
774
+        &mut f,
585775
         InstKind::Alloca(IrType::Int(IntWidth::I32)),
586
-        IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
587
-    let init = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
776
+        IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
777
+    );
778
+    let init = push(
779
+        &mut f,
780
+        InstKind::ConstInt(0, IntWidth::I32),
781
+        IrType::Int(IntWidth::I32),
782
+    );
588783
     push(&mut f, InstKind::Store(init, slot), IrType::Void);
589784
 
590785
     let header = f.create_block("header");
591786
     let i_param = f.next_value_id();
592
-    f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
787
+    f.block_mut(header).params.push(BlockParam {
788
+        id: i_param,
789
+        ty: IrType::Int(IntWidth::I32),
790
+    });
593791
     let v = f.next_value_id();
594792
     f.block_mut(header).insts.push(Inst {
595793
         id: v,
@@ -627,20 +825,32 @@ fn audit_licm_hoists_clean_alloca_load() {
627825
     // The const(1) inside the header IS loop-invariant — LICM should hoist it.
628826
     Licm.run(&mut m);
629827
     let entry_block = m.functions[0].block(m.functions[0].entry);
630
-    let const1_in_entry = entry_block.insts.iter()
828
+    let const1_in_entry = entry_block
829
+        .insts
830
+        .iter()
631831
         .any(|i| matches!(i.kind, InstKind::ConstInt(1, IntWidth::I32)));
632
-    assert!(const1_in_entry,
633
-        "LICM should have hoisted const(1) into the preheader");
832
+    assert!(
833
+        const1_in_entry,
834
+        "LICM should have hoisted const(1) into the preheader"
835
+    );
634836
     // The load is now loop-invariant too: no loop store/call can clobber it.
635837
     let header_block = &m.functions[0].blocks[1];
636
-    let load_still_in_header = header_block.insts.iter()
838
+    let load_still_in_header = header_block
839
+        .insts
840
+        .iter()
637841
         .any(|i| matches!(i.kind, InstKind::Load(_)));
638
-    assert!(!load_still_in_header,
639
-        "LICM should hoist a load when the loop is memory-clean");
640
-    let load_in_entry = entry_block.insts.iter()
842
+    assert!(
843
+        !load_still_in_header,
844
+        "LICM should hoist a load when the loop is memory-clean"
845
+    );
846
+    let load_in_entry = entry_block
847
+        .insts
848
+        .iter()
641849
         .any(|i| matches!(i.kind, InstKind::Load(_)));
642
-    assert!(load_in_entry,
643
-        "LICM should move the memory-clean load into the preheader");
850
+    assert!(
851
+        load_in_entry,
852
+        "LICM should move the memory-clean load into the preheader"
853
+    );
644854
 }
645855
 
646856
 // =============================================================
@@ -660,11 +870,18 @@ fn audit_pipeline_o2_e2e_loop_through_passmanager() {
660870
     //                         %d=icmp ge %i, %lim; cbr %d, exit, latch(%i2) }
661871
     //        latch(%i_in:i32) { %1=const 1; %n=iadd %i_in, %1; br header(%n) }
662872
     //        exit { ret }
663
-    let init = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
873
+    let init = push(
874
+        &mut f,
875
+        InstKind::ConstInt(0, IntWidth::I32),
876
+        IrType::Int(IntWidth::I32),
877
+    );
664878
 
665879
     let header = f.create_block("header");
666880
     let i_param = f.next_value_id();
667
-    f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
881
+    f.block_mut(header).params.push(BlockParam {
882
+        id: i_param,
883
+        ty: IrType::Int(IntWidth::I32),
884
+    });
668885
 
669886
     let k = f.next_value_id();
670887
     f.block_mut(header).insts.push(Inst {
@@ -697,7 +914,10 @@ fn audit_pipeline_o2_e2e_loop_through_passmanager() {
697914
 
698915
     let latch = f.create_block("latch");
699916
     let i_in = f.next_value_id();
700
-    f.block_mut(latch).params.push(BlockParam { id: i_in, ty: IrType::Int(IntWidth::I32) });
917
+    f.block_mut(latch).params.push(BlockParam {
918
+        id: i_in,
919
+        ty: IrType::Int(IntWidth::I32),
920
+    });
701921
     let one = f.next_value_id();
702922
     f.block_mut(latch).insts.push(Inst {
703923
         id: one,
@@ -736,7 +956,11 @@ fn audit_pipeline_o2_e2e_loop_through_passmanager() {
736956
 
737957
     // Final IR must verify.
738958
     let errs = verify_module(&m);
739
-    assert!(errs.is_empty(), "O2 pipeline left an invalid module: {:?}", errs);
959
+    assert!(
960
+        errs.is_empty(),
961
+        "O2 pipeline left an invalid module: {:?}",
962
+        errs
963
+    );
740964
 }
741965
 
742966
 // =============================================================
@@ -755,7 +979,11 @@ fn audit_interaction_const_prop_then_dce_removes_orphan_const() {
755979
     let mut f = Function::new("f".into(), vec![], IrType::Void);
756980
     let cond = push(&mut f, InstKind::ConstBool(true), IrType::Bool);
757981
     // This constant is ONLY used in the about-to-be-dead else block.
758
-    let dead_only = push(&mut f, InstKind::ConstInt(99, IntWidth::I32), IrType::Int(IntWidth::I32));
982
+    let dead_only = push(
983
+        &mut f,
984
+        InstKind::ConstInt(99, IntWidth::I32),
985
+        IrType::Int(IntWidth::I32),
986
+    );
759987
 
760988
     let then_b = f.create_block("then");
761989
     let else_b = f.create_block("else");
@@ -789,11 +1017,19 @@ fn audit_interaction_const_prop_then_dce_removes_orphan_const() {
7891017
 
7901018
     // After: else block gone, const(99) and ineg gone too.
7911019
     let f = &m.functions[0];
792
-    assert!(!f.blocks.iter().any(|b| b.id == else_b), "else block should be pruned");
793
-    let dead_remains = f.blocks.iter()
1020
+    assert!(
1021
+        !f.blocks.iter().any(|b| b.id == else_b),
1022
+        "else block should be pruned"
1023
+    );
1024
+    let dead_remains = f
1025
+        .blocks
1026
+        .iter()
7941027
         .flat_map(|b| b.insts.iter())
7951028
         .any(|i| matches!(i.kind, InstKind::ConstInt(99, _)));
796
-    assert!(!dead_remains, "const(99) should be DCE'd after const_prop drops its only use");
1029
+    assert!(
1030
+        !dead_remains,
1031
+        "const(99) should be DCE'd after const_prop drops its only use"
1032
+    );
7971033
 }
7981034
 
7991035
 // =============================================================
@@ -806,8 +1042,16 @@ fn audit_interaction_strength_reduce_orphans_get_dced() {
8061042
 
8071043
     let mut m = Module::new("t".into());
8081044
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
809
-    let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
810
-    let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1045
+    let x = push(
1046
+        &mut f,
1047
+        InstKind::ConstInt(42, IntWidth::I32),
1048
+        IrType::Int(IntWidth::I32),
1049
+    );
1050
+    let one = push(
1051
+        &mut f,
1052
+        InstKind::ConstInt(1, IntWidth::I32),
1053
+        IrType::Int(IntWidth::I32),
1054
+    );
8111055
     let mul = push(&mut f, InstKind::IMul(x, one), IrType::Int(IntWidth::I32));
8121056
     let entry = f.entry;
8131057
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(mul)));
@@ -830,11 +1074,15 @@ fn audit_interaction_strength_reduce_orphans_get_dced() {
8301074
     assert_eq!(term_val, x, "expected return to be x directly");
8311075
 
8321076
     // The orphan placeholder should be gone.
833
-    let extra_const = f.blocks[0].insts.iter()
1077
+    let extra_const = f.blocks[0]
1078
+        .insts
1079
+        .iter()
8341080
         .filter(|i| matches!(i.kind, InstKind::ConstInt(0, _)))
8351081
         .count();
836
-    assert_eq!(extra_const, 0,
837
-        "strength_reduce orphan placeholder Const(0) should be DCE'd");
1082
+    assert_eq!(
1083
+        extra_const, 0,
1084
+        "strength_reduce orphan placeholder Const(0) should be DCE'd"
1085
+    );
8381086
 }
8391087
 
8401088
 // =============================================================
@@ -847,15 +1095,27 @@ fn audit_const_fold_shl_at_width_bails() {
8471095
     // so the runtime answer is 1. The fold MUST NOT silently emit 0.
8481096
     let mut m = Module::new("t".into());
8491097
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
850
-    let v = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
851
-    let cnt = push(&mut f, InstKind::ConstInt(32, IntWidth::I32), IrType::Int(IntWidth::I32));
1098
+    let v = push(
1099
+        &mut f,
1100
+        InstKind::ConstInt(1, IntWidth::I32),
1101
+        IrType::Int(IntWidth::I32),
1102
+    );
1103
+    let cnt = push(
1104
+        &mut f,
1105
+        InstKind::ConstInt(32, IntWidth::I32),
1106
+        IrType::Int(IntWidth::I32),
1107
+    );
8521108
     let s = push(&mut f, InstKind::Shl(v, cnt), IrType::Int(IntWidth::I32));
8531109
     let entry = f.entry;
8541110
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
8551111
     m.add_function(f);
8561112
 
8571113
     ConstFold.run(&mut m);
858
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
1114
+    let folded = m.functions[0].blocks[0]
1115
+        .insts
1116
+        .iter()
1117
+        .find(|i| i.id == s)
1118
+        .unwrap();
8591119
     // Acceptable outcomes: leave the Shl alone, OR mask the count.
8601120
     // NOT acceptable: ConstInt(0, _).
8611121
     if let InstKind::ConstInt(0, _) = folded.kind {
@@ -870,15 +1130,27 @@ fn audit_const_fold_shl_at_width_bails() {
8701130
 fn audit_const_fold_shl_negative_count_bails() {
8711131
     let mut m = Module::new("t".into());
8721132
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
873
-    let v = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
874
-    let cnt = push(&mut f, InstKind::ConstInt(-1, IntWidth::I32), IrType::Int(IntWidth::I32));
1133
+    let v = push(
1134
+        &mut f,
1135
+        InstKind::ConstInt(7, IntWidth::I32),
1136
+        IrType::Int(IntWidth::I32),
1137
+    );
1138
+    let cnt = push(
1139
+        &mut f,
1140
+        InstKind::ConstInt(-1, IntWidth::I32),
1141
+        IrType::Int(IntWidth::I32),
1142
+    );
8751143
     let s = push(&mut f, InstKind::Shl(v, cnt), IrType::Int(IntWidth::I32));
8761144
     let entry = f.entry;
8771145
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
8781146
     m.add_function(f);
8791147
 
8801148
     ConstFold.run(&mut m);
881
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
1149
+    let folded = m.functions[0].blocks[0]
1150
+        .insts
1151
+        .iter()
1152
+        .find(|i| i.id == s)
1153
+        .unwrap();
8821154
     if let InstKind::ConstInt(0, _) = folded.kind {
8831155
         panic!("audit M-C: shl with negative count folded to 0 — wrong on AArch64");
8841156
     }
@@ -891,15 +1163,27 @@ fn audit_const_fold_shl_negative_count_bails() {
8911163
 fn audit_const_fold_lshr_negative_count_bails() {
8921164
     let mut m = Module::new("t".into());
8931165
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
894
-    let v = push(&mut f, InstKind::ConstInt(64, IntWidth::I32), IrType::Int(IntWidth::I32));
895
-    let cnt = push(&mut f, InstKind::ConstInt(-2, IntWidth::I32), IrType::Int(IntWidth::I32));
1166
+    let v = push(
1167
+        &mut f,
1168
+        InstKind::ConstInt(64, IntWidth::I32),
1169
+        IrType::Int(IntWidth::I32),
1170
+    );
1171
+    let cnt = push(
1172
+        &mut f,
1173
+        InstKind::ConstInt(-2, IntWidth::I32),
1174
+        IrType::Int(IntWidth::I32),
1175
+    );
8961176
     let s = push(&mut f, InstKind::LShr(v, cnt), IrType::Int(IntWidth::I32));
8971177
     let entry = f.entry;
8981178
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
8991179
     m.add_function(f);
9001180
 
9011181
     ConstFold.run(&mut m);
902
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
1182
+    let folded = m.functions[0].blocks[0]
1183
+        .insts
1184
+        .iter()
1185
+        .find(|i| i.id == s)
1186
+        .unwrap();
9031187
     if let InstKind::ConstInt(0, _) = folded.kind {
9041188
         panic!("audit M-C: lshr with negative count folded to 0");
9051189
     }
@@ -932,25 +1216,35 @@ fn audit_const_fold_width_drift_iadd() {
9321216
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
9331217
     let a = f.next_value_id();
9341218
     f.block_mut(f.entry).insts.push(Inst {
935
-        id: a, kind: InstKind::ConstInt(255, IntWidth::I8),
936
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1219
+        id: a,
1220
+        kind: InstKind::ConstInt(255, IntWidth::I8),
1221
+        ty: IrType::Int(IntWidth::I8),
1222
+        span: dummy_span(),
9371223
     });
9381224
     let b = f.next_value_id();
9391225
     f.block_mut(f.entry).insts.push(Inst {
940
-        id: b, kind: InstKind::ConstInt(2, IntWidth::I8),
941
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1226
+        id: b,
1227
+        kind: InstKind::ConstInt(2, IntWidth::I8),
1228
+        ty: IrType::Int(IntWidth::I8),
1229
+        span: dummy_span(),
9421230
     });
9431231
     let sum = f.next_value_id();
9441232
     f.block_mut(f.entry).insts.push(Inst {
945
-        id: sum, kind: InstKind::IAdd(a, b),
946
-        ty: IrType::Int(IntWidth::I32), span: dummy_span(),
1233
+        id: sum,
1234
+        kind: InstKind::IAdd(a, b),
1235
+        ty: IrType::Int(IntWidth::I32),
1236
+        span: dummy_span(),
9471237
     });
9481238
     let entry = f.entry;
9491239
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(sum)));
9501240
     m.add_function(f);
9511241
 
9521242
     ConstFold.run(&mut m);
953
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == sum).unwrap();
1243
+    let folded = m.functions[0].blocks[0]
1244
+        .insts
1245
+        .iter()
1246
+        .find(|i| i.id == sum)
1247
+        .unwrap();
9541248
     match folded.kind {
9551249
         InstKind::ConstInt(1, IntWidth::I32) => { /* good */ }
9561250
         InstKind::ConstInt(v, w) => panic!(
@@ -970,28 +1264,41 @@ fn audit_const_fold_width_drift_isub() {
9701264
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
9711265
     let a = f.next_value_id();
9721266
     f.block_mut(f.entry).insts.push(Inst {
973
-        id: a, kind: InstKind::ConstInt(250, IntWidth::I8),
974
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1267
+        id: a,
1268
+        kind: InstKind::ConstInt(250, IntWidth::I8),
1269
+        ty: IrType::Int(IntWidth::I8),
1270
+        span: dummy_span(),
9751271
     });
9761272
     let b = f.next_value_id();
9771273
     f.block_mut(f.entry).insts.push(Inst {
978
-        id: b, kind: InstKind::ConstInt(1, IntWidth::I8),
979
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1274
+        id: b,
1275
+        kind: InstKind::ConstInt(1, IntWidth::I8),
1276
+        ty: IrType::Int(IntWidth::I8),
1277
+        span: dummy_span(),
9801278
     });
9811279
     let diff = f.next_value_id();
9821280
     f.block_mut(f.entry).insts.push(Inst {
983
-        id: diff, kind: InstKind::ISub(a, b),
984
-        ty: IrType::Int(IntWidth::I32), span: dummy_span(),
1281
+        id: diff,
1282
+        kind: InstKind::ISub(a, b),
1283
+        ty: IrType::Int(IntWidth::I32),
1284
+        span: dummy_span(),
9851285
     });
9861286
     let entry = f.entry;
9871287
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(diff)));
9881288
     m.add_function(f);
9891289
 
9901290
     ConstFold.run(&mut m);
991
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == diff).unwrap();
1291
+    let folded = m.functions[0].blocks[0]
1292
+        .insts
1293
+        .iter()
1294
+        .find(|i| i.id == diff)
1295
+        .unwrap();
9921296
     match folded.kind {
9931297
         InstKind::ConstInt(-7, IntWidth::I32) => { /* good */ }
994
-        ref other => panic!("audit N-1 ISub: expected ConstInt(-7, I32), got {:?}", other),
1298
+        ref other => panic!(
1299
+            "audit N-1 ISub: expected ConstInt(-7, I32), got {:?}",
1300
+            other
1301
+        ),
9951302
     }
9961303
 }
9971304
 
@@ -1004,28 +1311,41 @@ fn audit_const_fold_width_drift_imul() {
10041311
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
10051312
     let a = f.next_value_id();
10061313
     f.block_mut(f.entry).insts.push(Inst {
1007
-        id: a, kind: InstKind::ConstInt(255, IntWidth::I8),
1008
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1314
+        id: a,
1315
+        kind: InstKind::ConstInt(255, IntWidth::I8),
1316
+        ty: IrType::Int(IntWidth::I8),
1317
+        span: dummy_span(),
10091318
     });
10101319
     let b = f.next_value_id();
10111320
     f.block_mut(f.entry).insts.push(Inst {
1012
-        id: b, kind: InstKind::ConstInt(3, IntWidth::I8),
1013
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1321
+        id: b,
1322
+        kind: InstKind::ConstInt(3, IntWidth::I8),
1323
+        ty: IrType::Int(IntWidth::I8),
1324
+        span: dummy_span(),
10141325
     });
10151326
     let prod = f.next_value_id();
10161327
     f.block_mut(f.entry).insts.push(Inst {
1017
-        id: prod, kind: InstKind::IMul(a, b),
1018
-        ty: IrType::Int(IntWidth::I32), span: dummy_span(),
1328
+        id: prod,
1329
+        kind: InstKind::IMul(a, b),
1330
+        ty: IrType::Int(IntWidth::I32),
1331
+        span: dummy_span(),
10191332
     });
10201333
     let entry = f.entry;
10211334
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(prod)));
10221335
     m.add_function(f);
10231336
 
10241337
     ConstFold.run(&mut m);
1025
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == prod).unwrap();
1338
+    let folded = m.functions[0].blocks[0]
1339
+        .insts
1340
+        .iter()
1341
+        .find(|i| i.id == prod)
1342
+        .unwrap();
10261343
     match folded.kind {
10271344
         InstKind::ConstInt(-3, IntWidth::I32) => { /* good */ }
1028
-        ref other => panic!("audit N-1 IMul: expected ConstInt(-3, I32), got {:?}", other),
1345
+        ref other => panic!(
1346
+            "audit N-1 IMul: expected ConstInt(-3, I32), got {:?}",
1347
+            other
1348
+        ),
10291349
     }
10301350
 }
10311351
 
@@ -1039,25 +1359,35 @@ fn audit_const_fold_width_drift_idiv() {
10391359
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
10401360
     let a = f.next_value_id();
10411361
     f.block_mut(f.entry).insts.push(Inst {
1042
-        id: a, kind: InstKind::ConstInt(255, IntWidth::I8),
1043
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1362
+        id: a,
1363
+        kind: InstKind::ConstInt(255, IntWidth::I8),
1364
+        ty: IrType::Int(IntWidth::I8),
1365
+        span: dummy_span(),
10441366
     });
10451367
     let b = f.next_value_id();
10461368
     f.block_mut(f.entry).insts.push(Inst {
1047
-        id: b, kind: InstKind::ConstInt(2, IntWidth::I8),
1048
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1369
+        id: b,
1370
+        kind: InstKind::ConstInt(2, IntWidth::I8),
1371
+        ty: IrType::Int(IntWidth::I8),
1372
+        span: dummy_span(),
10491373
     });
10501374
     let q = f.next_value_id();
10511375
     f.block_mut(f.entry).insts.push(Inst {
1052
-        id: q, kind: InstKind::IDiv(a, b),
1053
-        ty: IrType::Int(IntWidth::I32), span: dummy_span(),
1376
+        id: q,
1377
+        kind: InstKind::IDiv(a, b),
1378
+        ty: IrType::Int(IntWidth::I32),
1379
+        span: dummy_span(),
10541380
     });
10551381
     let entry = f.entry;
10561382
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(q)));
10571383
     m.add_function(f);
10581384
 
10591385
     ConstFold.run(&mut m);
1060
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == q).unwrap();
1386
+    let folded = m.functions[0].blocks[0]
1387
+        .insts
1388
+        .iter()
1389
+        .find(|i| i.id == q)
1390
+        .unwrap();
10611391
     match folded.kind {
10621392
         InstKind::ConstInt(0, IntWidth::I32) => { /* good */ }
10631393
         ref other => panic!("audit N-1 IDiv: expected ConstInt(0, I32), got {:?}", other),
@@ -1074,25 +1404,35 @@ fn audit_const_fold_width_drift_icmp() {
10741404
     let mut f = Function::new("f".into(), vec![], IrType::Bool);
10751405
     let a = f.next_value_id();
10761406
     f.block_mut(f.entry).insts.push(Inst {
1077
-        id: a, kind: InstKind::ConstInt(255, IntWidth::I8),
1078
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1407
+        id: a,
1408
+        kind: InstKind::ConstInt(255, IntWidth::I8),
1409
+        ty: IrType::Int(IntWidth::I8),
1410
+        span: dummy_span(),
10791411
     });
10801412
     let b = f.next_value_id();
10811413
     f.block_mut(f.entry).insts.push(Inst {
1082
-        id: b, kind: InstKind::ConstInt(0, IntWidth::I8),
1083
-        ty: IrType::Int(IntWidth::I8), span: dummy_span(),
1414
+        id: b,
1415
+        kind: InstKind::ConstInt(0, IntWidth::I8),
1416
+        ty: IrType::Int(IntWidth::I8),
1417
+        span: dummy_span(),
10841418
     });
10851419
     let lt = f.next_value_id();
10861420
     f.block_mut(f.entry).insts.push(Inst {
1087
-        id: lt, kind: InstKind::ICmp(CmpOp::Lt, a, b),
1088
-        ty: IrType::Bool, span: dummy_span(),
1421
+        id: lt,
1422
+        kind: InstKind::ICmp(CmpOp::Lt, a, b),
1423
+        ty: IrType::Bool,
1424
+        span: dummy_span(),
10891425
     });
10901426
     let entry = f.entry;
10911427
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(lt)));
10921428
     m.add_function(f);
10931429
 
10941430
     ConstFold.run(&mut m);
1095
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == lt).unwrap();
1431
+    let folded = m.functions[0].blocks[0]
1432
+        .insts
1433
+        .iter()
1434
+        .find(|i| i.id == lt)
1435
+        .unwrap();
10961436
     match folded.kind {
10971437
         InstKind::ConstBool(true) => { /* good */ }
10981438
         ref other => panic!("audit N-1 ICmp: expected ConstBool(true), got {:?}", other),
@@ -1112,13 +1452,25 @@ fn audit_cse_dedupes_const_int_bit_pattern() {
11121452
     use crate::opt::LocalCse;
11131453
     let mut m = Module::new("t".into());
11141454
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I8));
1115
-    let a = push(&mut f, InstKind::ConstInt(255, IntWidth::I8), IrType::Int(IntWidth::I8));
1116
-    let b = push(&mut f, InstKind::ConstInt(-1,  IntWidth::I8), IrType::Int(IntWidth::I8));
1455
+    let a = push(
1456
+        &mut f,
1457
+        InstKind::ConstInt(255, IntWidth::I8),
1458
+        IrType::Int(IntWidth::I8),
1459
+    );
1460
+    let b = push(
1461
+        &mut f,
1462
+        InstKind::ConstInt(-1, IntWidth::I8),
1463
+        IrType::Int(IntWidth::I8),
1464
+    );
11171465
     // Use a in some op and b in another so neither is dead.
11181466
     let neg_a = push(&mut f, InstKind::INeg(a), IrType::Int(IntWidth::I8));
11191467
     let neg_b = push(&mut f, InstKind::INeg(b), IrType::Int(IntWidth::I8));
11201468
     // Add them so both are live to the terminator.
1121
-    let sum = push(&mut f, InstKind::IAdd(neg_a, neg_b), IrType::Int(IntWidth::I8));
1469
+    let sum = push(
1470
+        &mut f,
1471
+        InstKind::IAdd(neg_a, neg_b),
1472
+        IrType::Int(IntWidth::I8),
1473
+    );
11221474
     let entry = f.entry;
11231475
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(sum)));
11241476
     m.add_function(f);
@@ -1130,11 +1482,19 @@ fn audit_cse_dedupes_const_int_bit_pattern() {
11301482
     let f = &m.functions[0];
11311483
     let neg_a_inst = f.blocks[0].insts.iter().find(|i| i.id == neg_a).unwrap();
11321484
     let neg_b_inst = f.blocks[0].insts.iter().find(|i| i.id == neg_b).unwrap();
1133
-    let neg_a_op = match &neg_a_inst.kind { InstKind::INeg(v) => *v, _ => panic!() };
1134
-    let neg_b_op = match &neg_b_inst.kind { InstKind::INeg(v) => *v, _ => panic!() };
1135
-    assert_eq!(neg_a_op, neg_b_op,
1485
+    let neg_a_op = match &neg_a_inst.kind {
1486
+        InstKind::INeg(v) => *v,
1487
+        _ => panic!(),
1488
+    };
1489
+    let neg_b_op = match &neg_b_inst.kind {
1490
+        InstKind::INeg(v) => *v,
1491
+        _ => panic!(),
1492
+    };
1493
+    assert_eq!(
1494
+        neg_a_op, neg_b_op,
11361495
         "audit B-8: ConstInt(255, I8) and ConstInt(-1, I8) should CSE-dedupe \
1137
-         (both represent -1 at i8 precision), but the INeg operands differ");
1496
+         (both represent -1 at i8 precision), but the INeg operands differ"
1497
+    );
11381498
 }
11391499
 
11401500
 // =============================================================
@@ -1144,15 +1504,27 @@ fn audit_cse_dedupes_const_int_bit_pattern() {
11441504
 fn audit_const_fold_ashr_negative_count_bails() {
11451505
     let mut m = Module::new("t".into());
11461506
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1147
-    let v = push(&mut f, InstKind::ConstInt(-128, IntWidth::I32), IrType::Int(IntWidth::I32));
1148
-    let cnt = push(&mut f, InstKind::ConstInt(-3, IntWidth::I32), IrType::Int(IntWidth::I32));
1507
+    let v = push(
1508
+        &mut f,
1509
+        InstKind::ConstInt(-128, IntWidth::I32),
1510
+        IrType::Int(IntWidth::I32),
1511
+    );
1512
+    let cnt = push(
1513
+        &mut f,
1514
+        InstKind::ConstInt(-3, IntWidth::I32),
1515
+        IrType::Int(IntWidth::I32),
1516
+    );
11491517
     let s = push(&mut f, InstKind::AShr(v, cnt), IrType::Int(IntWidth::I32));
11501518
     let entry = f.entry;
11511519
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
11521520
     m.add_function(f);
11531521
 
11541522
     ConstFold.run(&mut m);
1155
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
1523
+    let folded = m.functions[0].blocks[0]
1524
+        .insts
1525
+        .iter()
1526
+        .find(|i| i.id == s)
1527
+        .unwrap();
11561528
     if let InstKind::ConstInt(0, _) = folded.kind {
11571529
         panic!("audit M-C: ashr with negative count folded to 0 — wrong on AArch64");
11581530
     }
@@ -1169,13 +1541,28 @@ fn audit_licm_does_not_hoist_idiv() {
11691541
     // skipped it (causing SIGFPE on b == 0).
11701542
     let mut m = Module::new("t".into());
11711543
     let mut f = Function::new("f".into(), vec![], IrType::Void);
1172
-    let a = push(&mut f, InstKind::ConstInt(100, IntWidth::I32), IrType::Int(IntWidth::I32));
1173
-    let b = push(&mut f, InstKind::ConstInt(5,   IntWidth::I32), IrType::Int(IntWidth::I32));
1174
-    let init = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
1544
+    let a = push(
1545
+        &mut f,
1546
+        InstKind::ConstInt(100, IntWidth::I32),
1547
+        IrType::Int(IntWidth::I32),
1548
+    );
1549
+    let b = push(
1550
+        &mut f,
1551
+        InstKind::ConstInt(5, IntWidth::I32),
1552
+        IrType::Int(IntWidth::I32),
1553
+    );
1554
+    let init = push(
1555
+        &mut f,
1556
+        InstKind::ConstInt(0, IntWidth::I32),
1557
+        IrType::Int(IntWidth::I32),
1558
+    );
11751559
 
11761560
     let header = f.create_block("header");
11771561
     let i_param = f.next_value_id();
1178
-    f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
1562
+    f.block_mut(header).params.push(BlockParam {
1563
+        id: i_param,
1564
+        ty: IrType::Int(IntWidth::I32),
1565
+    });
11791566
 
11801567
     // Inside the body: %q = idiv a, b — both operands invariant.
11811568
     let q = f.next_value_id();
@@ -1224,12 +1611,28 @@ fn audit_licm_does_not_hoist_idiv() {
12241611
     Licm.run(&mut m);
12251612
     let f = &m.functions[0];
12261613
     // The IDiv must STILL be in the header block, not in entry.
1227
-    let header_block = f.blocks.iter().find(|b| b.name.starts_with("header")).unwrap();
1614
+    let header_block = f
1615
+        .blocks
1616
+        .iter()
1617
+        .find(|b| b.name.starts_with("header"))
1618
+        .unwrap();
12281619
     let entry_block = f.block(f.entry);
1229
-    let idiv_in_header = header_block.insts.iter().any(|i| matches!(i.kind, InstKind::IDiv(..)));
1230
-    let idiv_in_entry  = entry_block.insts.iter().any(|i| matches!(i.kind, InstKind::IDiv(..)));
1231
-    assert!(idiv_in_header, "audit Med-6: LICM should leave IDiv in body (trap-prone)");
1232
-    assert!(!idiv_in_entry, "audit Med-6: LICM must not hoist IDiv into preheader");
1620
+    let idiv_in_header = header_block
1621
+        .insts
1622
+        .iter()
1623
+        .any(|i| matches!(i.kind, InstKind::IDiv(..)));
1624
+    let idiv_in_entry = entry_block
1625
+        .insts
1626
+        .iter()
1627
+        .any(|i| matches!(i.kind, InstKind::IDiv(..)));
1628
+    assert!(
1629
+        idiv_in_header,
1630
+        "audit Med-6: LICM should leave IDiv in body (trap-prone)"
1631
+    );
1632
+    assert!(
1633
+        !idiv_in_entry,
1634
+        "audit Med-6: LICM must not hoist IDiv into preheader"
1635
+    );
12331636
 }
12341637
 
12351638
 // =============================================================
@@ -1243,16 +1646,32 @@ fn audit_licm_does_not_hoist_idiv() {
12431646
 fn audit_const_fold_select_uses_declared_type() {
12441647
     let mut m = Module::new("t".into());
12451648
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1246
-    let a = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1247
-    let b = push(&mut f, InstKind::ConstInt(99, IntWidth::I32), IrType::Int(IntWidth::I32));
1649
+    let a = push(
1650
+        &mut f,
1651
+        InstKind::ConstInt(1, IntWidth::I32),
1652
+        IrType::Int(IntWidth::I32),
1653
+    );
1654
+    let b = push(
1655
+        &mut f,
1656
+        InstKind::ConstInt(99, IntWidth::I32),
1657
+        IrType::Int(IntWidth::I32),
1658
+    );
12481659
     let cond = push(&mut f, InstKind::ConstBool(true), IrType::Bool);
1249
-    let sel = push(&mut f, InstKind::Select(cond, a, b), IrType::Int(IntWidth::I32));
1660
+    let sel = push(
1661
+        &mut f,
1662
+        InstKind::Select(cond, a, b),
1663
+        IrType::Int(IntWidth::I32),
1664
+    );
12501665
     let entry = f.entry;
12511666
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(sel)));
12521667
     m.add_function(f);
12531668
 
12541669
     ConstFold.run(&mut m);
1255
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == sel).unwrap();
1670
+    let folded = m.functions[0].blocks[0]
1671
+        .insts
1672
+        .iter()
1673
+        .find(|i| i.id == sel)
1674
+        .unwrap();
12561675
     match folded.kind {
12571676
         InstKind::ConstInt(1, IntWidth::I32) => { /* good */ }
12581677
         ref other => panic!("expected ConstInt(1, I32), got {:?}", other),
@@ -1292,7 +1711,11 @@ fn audit_const_fold_select_width_drift_int() {
12921711
         ty: IrType::Int(IntWidth::I8),
12931712
         span: dummy_span(),
12941713
     });
1295
-    let b = push(&mut f, InstKind::ConstInt(99, IntWidth::I64), IrType::Int(IntWidth::I64));
1714
+    let b = push(
1715
+        &mut f,
1716
+        InstKind::ConstInt(99, IntWidth::I64),
1717
+        IrType::Int(IntWidth::I64),
1718
+    );
12961719
     let cond = push(&mut f, InstKind::ConstBool(true), IrType::Bool);
12971720
 
12981721
     // Select declared as i64, chosen branch is i8 (255 → -1).
@@ -1307,7 +1730,11 @@ fn audit_const_fold_select_width_drift_int() {
13071730
     m.add_function(f);
13081731
 
13091732
     ConstFold.run(&mut m);
1310
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == sel).unwrap();
1733
+    let folded = m.functions[0].blocks[0]
1734
+        .insts
1735
+        .iter()
1736
+        .find(|i| i.id == sel)
1737
+        .unwrap();
13111738
     match folded.kind {
13121739
         InstKind::ConstInt(-1, IntWidth::I64) => { /* good — i8 -1 sign-extended to i64 */ }
13131740
         InstKind::ConstInt(v, w) => panic!(
@@ -1338,8 +1765,16 @@ fn audit_const_fold_select_width_drift_int() {
13381765
 fn audit_strength_reduce_identity_does_not_write_placeholder() {
13391766
     let mut m = Module::new("t".into());
13401767
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1341
-    let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
1342
-    let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1768
+    let x = push(
1769
+        &mut f,
1770
+        InstKind::ConstInt(42, IntWidth::I32),
1771
+        IrType::Int(IntWidth::I32),
1772
+    );
1773
+    let one = push(
1774
+        &mut f,
1775
+        InstKind::ConstInt(1, IntWidth::I32),
1776
+        IrType::Int(IntWidth::I32),
1777
+    );
13431778
     let mul = push(&mut f, InstKind::IMul(x, one), IrType::Int(IntWidth::I32));
13441779
     let entry = f.entry;
13451780
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(mul)));
@@ -1349,7 +1784,11 @@ fn audit_strength_reduce_identity_does_not_write_placeholder() {
13491784
     // The orphan instruction at `mul`'s ID must still exist and
13501785
     // have its original kind. The earlier (broken) version would
13511786
     // have replaced its kind with ConstInt(0, _).
1352
-    let orphan = m.functions[0].blocks[0].insts.iter().find(|i| i.id == mul).unwrap();
1787
+    let orphan = m.functions[0].blocks[0]
1788
+        .insts
1789
+        .iter()
1790
+        .find(|i| i.id == mul)
1791
+        .unwrap();
13531792
     match orphan.kind {
13541793
         InstKind::IMul(_, _) => { /* good — original kind preserved */ }
13551794
         InstKind::ConstInt(0, _) => panic!(
@@ -1369,15 +1808,26 @@ fn audit_strength_reduce_identity_does_not_write_placeholder() {
13691808
 fn audit_strength_reduce_identity_reports_changed() {
13701809
     let mut m = Module::new("t".into());
13711810
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1372
-    let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
1373
-    let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1811
+    let x = push(
1812
+        &mut f,
1813
+        InstKind::ConstInt(42, IntWidth::I32),
1814
+        IrType::Int(IntWidth::I32),
1815
+    );
1816
+    let one = push(
1817
+        &mut f,
1818
+        InstKind::ConstInt(1, IntWidth::I32),
1819
+        IrType::Int(IntWidth::I32),
1820
+    );
13741821
     let mul = push(&mut f, InstKind::IMul(x, one), IrType::Int(IntWidth::I32));
13751822
     let entry = f.entry;
13761823
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(mul)));
13771824
     m.add_function(f);
13781825
 
13791826
     let changed = StrengthReduce.run(&mut m);
1380
-    assert!(changed, "strength_reduce must report `changed = true` after Identity rewrite");
1827
+    assert!(
1828
+        changed,
1829
+        "strength_reduce must report `changed = true` after Identity rewrite"
1830
+    );
13811831
 
13821832
     // The terminator now references x.
13831833
     match m.functions[0].blocks[0].terminator.as_ref().unwrap() {
@@ -1403,15 +1853,27 @@ fn audit_const_fold_icmp_uses_each_operand_width() {
14031853
     // be FALSE: 255 != -1.
14041854
     let mut m = Module::new("t".into());
14051855
     let mut f = Function::new("f".into(), vec![], IrType::Bool);
1406
-    let a = push(&mut f, InstKind::ConstInt(255, IntWidth::I32), IrType::Int(IntWidth::I32));
1407
-    let b = push(&mut f, InstKind::ConstInt(255, IntWidth::I8),  IrType::Int(IntWidth::I8));
1856
+    let a = push(
1857
+        &mut f,
1858
+        InstKind::ConstInt(255, IntWidth::I32),
1859
+        IrType::Int(IntWidth::I32),
1860
+    );
1861
+    let b = push(
1862
+        &mut f,
1863
+        InstKind::ConstInt(255, IntWidth::I8),
1864
+        IrType::Int(IntWidth::I8),
1865
+    );
14081866
     let eq = push(&mut f, InstKind::ICmp(CmpOp::Eq, a, b), IrType::Bool);
14091867
     let entry = f.entry;
14101868
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(eq)));
14111869
     m.add_function(f);
14121870
 
14131871
     ConstFold.run(&mut m);
1414
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == eq).unwrap();
1872
+    let folded = m.functions[0].blocks[0]
1873
+        .insts
1874
+        .iter()
1875
+        .find(|i| i.id == eq)
1876
+        .unwrap();
14151877
     match folded.kind {
14161878
         // After the M-D fix: bv sign-extended at i8 → -1; av at i32 → 255.
14171879
         // 255 == -1 → false.
@@ -1436,18 +1898,37 @@ fn audit_const_fold_fcmp_f32_after_m1_fix() {
14361898
     // ConstFloat(16777216.0, F32) should now return true.
14371899
     let mut m = Module::new("t".into());
14381900
     let mut f = Function::new("f".into(), vec![], IrType::Bool);
1439
-    let i = push(&mut f, InstKind::ConstInt(16_777_217, IntWidth::I32), IrType::Int(IntWidth::I32));
1440
-    let fv_a = push(&mut f, InstKind::IntToFloat(i, FloatWidth::F32), IrType::Float(FloatWidth::F32));
1441
-    let fv_b = push(&mut f, InstKind::ConstFloat(16_777_216.0, FloatWidth::F32), IrType::Float(FloatWidth::F32));
1901
+    let i = push(
1902
+        &mut f,
1903
+        InstKind::ConstInt(16_777_217, IntWidth::I32),
1904
+        IrType::Int(IntWidth::I32),
1905
+    );
1906
+    let fv_a = push(
1907
+        &mut f,
1908
+        InstKind::IntToFloat(i, FloatWidth::F32),
1909
+        IrType::Float(FloatWidth::F32),
1910
+    );
1911
+    let fv_b = push(
1912
+        &mut f,
1913
+        InstKind::ConstFloat(16_777_216.0, FloatWidth::F32),
1914
+        IrType::Float(FloatWidth::F32),
1915
+    );
14421916
     let eq = push(&mut f, InstKind::FCmp(CmpOp::Eq, fv_a, fv_b), IrType::Bool);
14431917
     let entry = f.entry;
14441918
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(eq)));
14451919
     m.add_function(f);
14461920
 
14471921
     ConstFold.run(&mut m);
1448
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == eq).unwrap();
1449
-    assert!(matches!(folded.kind, InstKind::ConstBool(true)),
1450
-        "audit M-E: FCmp on f32-rounded values should return true, got {:?}", folded.kind);
1922
+    let folded = m.functions[0].blocks[0]
1923
+        .insts
1924
+        .iter()
1925
+        .find(|i| i.id == eq)
1926
+        .unwrap();
1927
+    assert!(
1928
+        matches!(folded.kind, InstKind::ConstBool(true)),
1929
+        "audit M-E: FCmp on f32-rounded values should return true, got {:?}",
1930
+        folded.kind
1931
+    );
14511932
 }
14521933
 
14531934
 // =============================================================
@@ -1460,18 +1941,37 @@ fn audit_const_fold_floattoint_from_f32_after_m1_fix() {
14601941
     // FloatToInt(_, I32) should produce 16777216, not 16777217.
14611942
     let mut m = Module::new("t".into());
14621943
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1463
-    let i = push(&mut f, InstKind::ConstInt(16_777_217, IntWidth::I32), IrType::Int(IntWidth::I32));
1464
-    let fv = push(&mut f, InstKind::IntToFloat(i, FloatWidth::F32), IrType::Float(FloatWidth::F32));
1465
-    let back = push(&mut f, InstKind::FloatToInt(fv, IntWidth::I32), IrType::Int(IntWidth::I32));
1944
+    let i = push(
1945
+        &mut f,
1946
+        InstKind::ConstInt(16_777_217, IntWidth::I32),
1947
+        IrType::Int(IntWidth::I32),
1948
+    );
1949
+    let fv = push(
1950
+        &mut f,
1951
+        InstKind::IntToFloat(i, FloatWidth::F32),
1952
+        IrType::Float(FloatWidth::F32),
1953
+    );
1954
+    let back = push(
1955
+        &mut f,
1956
+        InstKind::FloatToInt(fv, IntWidth::I32),
1957
+        IrType::Int(IntWidth::I32),
1958
+    );
14661959
     let entry = f.entry;
14671960
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(back)));
14681961
     m.add_function(f);
14691962
 
14701963
     ConstFold.run(&mut m);
1471
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == back).unwrap();
1964
+    let folded = m.functions[0].blocks[0]
1965
+        .insts
1966
+        .iter()
1967
+        .find(|i| i.id == back)
1968
+        .unwrap();
14721969
     match folded.kind {
14731970
         InstKind::ConstInt(16_777_216, IntWidth::I32) => { /* good */ }
1474
-        ref other => panic!("audit M-F: expected ConstInt(16777216, I32), got {:?}", other),
1971
+        ref other => panic!(
1972
+            "audit M-F: expected ConstInt(16777216, I32), got {:?}",
1973
+            other
1974
+        ),
14751975
     }
14761976
 }
14771977
 
@@ -1486,14 +1986,22 @@ fn audit_const_fold_popcount_uses_inst_ty() {
14861986
     // change makes the source carry a different width.
14871987
     let mut m = Module::new("t".into());
14881988
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1489
-    let v = push(&mut f, InstKind::ConstInt(0xFF, IntWidth::I32), IrType::Int(IntWidth::I32));
1989
+    let v = push(
1990
+        &mut f,
1991
+        InstKind::ConstInt(0xFF, IntWidth::I32),
1992
+        IrType::Int(IntWidth::I32),
1993
+    );
14901994
     let pc = push(&mut f, InstKind::PopCount(v), IrType::Int(IntWidth::I32));
14911995
     let entry = f.entry;
14921996
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(pc)));
14931997
     m.add_function(f);
14941998
 
14951999
     ConstFold.run(&mut m);
1496
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == pc).unwrap();
2000
+    let folded = m.functions[0].blocks[0]
2001
+        .insts
2002
+        .iter()
2003
+        .find(|i| i.id == pc)
2004
+        .unwrap();
14972005
     match folded.kind {
14982006
         InstKind::ConstInt(8, IntWidth::I32) => { /* good */ }
14992007
         ref other => panic!("expected ConstInt(8, I32), got {:?}", other),
@@ -1514,23 +2022,50 @@ fn audit_const_fold_popcount_uses_inst_ty() {
15142022
 fn audit_int_to_f32_then_fsub_wrong_answer_today() {
15152023
     let mut m = Module::new("t".into());
15162024
     let mut f = Function::new("f".into(), vec![], IrType::Float(FloatWidth::F32));
1517
-    let i_a = push(&mut f, InstKind::ConstInt(16_777_217, IntWidth::I32), IrType::Int(IntWidth::I32));
1518
-    let i_b = push(&mut f, InstKind::ConstInt(16_777_216, IntWidth::I32), IrType::Int(IntWidth::I32));
1519
-    let f_a = push(&mut f, InstKind::IntToFloat(i_a, FloatWidth::F32), IrType::Float(FloatWidth::F32));
1520
-    let f_b = push(&mut f, InstKind::IntToFloat(i_b, FloatWidth::F32), IrType::Float(FloatWidth::F32));
1521
-    let diff = push(&mut f, InstKind::FSub(f_a, f_b), IrType::Float(FloatWidth::F32));
2025
+    let i_a = push(
2026
+        &mut f,
2027
+        InstKind::ConstInt(16_777_217, IntWidth::I32),
2028
+        IrType::Int(IntWidth::I32),
2029
+    );
2030
+    let i_b = push(
2031
+        &mut f,
2032
+        InstKind::ConstInt(16_777_216, IntWidth::I32),
2033
+        IrType::Int(IntWidth::I32),
2034
+    );
2035
+    let f_a = push(
2036
+        &mut f,
2037
+        InstKind::IntToFloat(i_a, FloatWidth::F32),
2038
+        IrType::Float(FloatWidth::F32),
2039
+    );
2040
+    let f_b = push(
2041
+        &mut f,
2042
+        InstKind::IntToFloat(i_b, FloatWidth::F32),
2043
+        IrType::Float(FloatWidth::F32),
2044
+    );
2045
+    let diff = push(
2046
+        &mut f,
2047
+        InstKind::FSub(f_a, f_b),
2048
+        IrType::Float(FloatWidth::F32),
2049
+    );
15222050
     let entry = f.entry;
15232051
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(diff)));
15242052
     m.add_function(f);
15252053
 
15262054
     ConstFold.run(&mut m);
15272055
 
1528
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == diff).unwrap();
2056
+    let folded = m.functions[0].blocks[0]
2057
+        .insts
2058
+        .iter()
2059
+        .find(|i| i.id == diff)
2060
+        .unwrap();
15292061
     match folded.kind {
15302062
         // Expected: 0.0 (after correct f32 rounding both inputs are 16777216).
15312063
         // Bug:      1.0 (without rounding 16777217.0 - 16777216.0 = 1.0).
1532
-        InstKind::ConstFloat(v, FloatWidth::F32) => assert_eq!(v, 0.0,
1533
-            "expected 0.0 (both inputs round to 16777216 in f32), got {}", v),
2064
+        InstKind::ConstFloat(v, FloatWidth::F32) => assert_eq!(
2065
+            v, 0.0,
2066
+            "expected 0.0 (both inputs round to 16777216 in f32), got {}",
2067
+            v
2068
+        ),
15342069
         ref other => panic!("expected ConstFloat, got {:?}", other),
15352070
     }
15362071
 }
@@ -1542,15 +2077,27 @@ fn audit_int_to_f32_then_fsub_wrong_answer_today() {
15422077
 fn audit_const_fold_imul_i8_overflow_wraps() {
15432078
     let mut m = Module::new("t".into());
15442079
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I8));
1545
-    let a = push(&mut f, InstKind::ConstInt(100, IntWidth::I8), IrType::Int(IntWidth::I8));
1546
-    let b = push(&mut f, InstKind::ConstInt(100, IntWidth::I8), IrType::Int(IntWidth::I8));
2080
+    let a = push(
2081
+        &mut f,
2082
+        InstKind::ConstInt(100, IntWidth::I8),
2083
+        IrType::Int(IntWidth::I8),
2084
+    );
2085
+    let b = push(
2086
+        &mut f,
2087
+        InstKind::ConstInt(100, IntWidth::I8),
2088
+        IrType::Int(IntWidth::I8),
2089
+    );
15472090
     let p = push(&mut f, InstKind::IMul(a, b), IrType::Int(IntWidth::I8));
15482091
     let entry = f.entry;
15492092
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(p)));
15502093
     m.add_function(f);
15512094
 
15522095
     ConstFold.run(&mut m);
1553
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == p).unwrap();
2096
+    let folded = m.functions[0].blocks[0]
2097
+        .insts
2098
+        .iter()
2099
+        .find(|i| i.id == p)
2100
+        .unwrap();
15542101
     match folded.kind {
15552102
         // 100 * 100 = 10000; low byte = 0x10 = 16; sext = 16
15562103
         InstKind::ConstInt(v, IntWidth::I8) => assert_eq!(v, 16, "expected i8 wrap, got {}", v),
@@ -1583,7 +2130,11 @@ fn audit_const_fold_non_rpo_block_order() {
15832130
 
15842131
     let a_block = f.create_block("a");
15852132
     let b_block = f.create_block("b");
1586
-    let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
2133
+    let one = push(
2134
+        &mut f,
2135
+        InstKind::ConstInt(1, IntWidth::I32),
2136
+        IrType::Int(IntWidth::I32),
2137
+    );
15872138
     let entry = f.entry;
15882139
     f.block_mut(entry).terminator = Some(Terminator::Branch(a_block, vec![]));
15892140
 
@@ -1616,20 +2167,28 @@ fn audit_const_fold_non_rpo_block_order() {
16162167
     pm.run(&mut m);
16172168
 
16182169
     let post = verify_module(&m);
1619
-    assert!(post.is_empty(), "non-RPO block order broke optimization: {:?}", post);
2170
+    assert!(
2171
+        post.is_empty(),
2172
+        "non-RPO block order broke optimization: {:?}",
2173
+        post
2174
+    );
16202175
 
16212176
     // The fold MUST have converged: the IAdd's defining instruction
16222177
     // (still carrying `sum_id`) should now be the constant `3`, or
16232178
     // the entire dead chain should have been DCE'd and the terminator
16242179
     // should reference a const(3) directly.
16252180
     let f = &m.functions[0];
1626
-    let terminator_val = f.blocks.iter()
2181
+    let terminator_val = f
2182
+        .blocks
2183
+        .iter()
16272184
         .find_map(|b| match &b.terminator {
16282185
             Some(Terminator::Return(Some(v))) => Some(*v),
16292186
             _ => None,
16302187
         })
16312188
         .expect("no Return terminator");
1632
-    let term_kind = f.blocks.iter()
2189
+    let term_kind = f
2190
+        .blocks
2191
+        .iter()
16332192
         .flat_map(|b| b.insts.iter())
16342193
         .find(|i| i.id == terminator_val)
16352194
         .map(|i| i.kind.clone())
@@ -1705,7 +2264,7 @@ fn audit_const_fold_inner_fixpoint_across_vec_order() {
17052264
     let a_sum = f.next_value_id();
17062265
     f.block_mut(a_block).insts.push(Inst {
17072266
         id: a_sum,
1708
-        kind: InstKind::IAdd(c1, c2),    // folds to const(30)
2267
+        kind: InstKind::IAdd(c1, c2), // folds to const(30)
17092268
         ty: IrType::Int(IntWidth::I32),
17102269
         span: dummy_span(),
17112270
     });
@@ -1722,7 +2281,7 @@ fn audit_const_fold_inner_fixpoint_across_vec_order() {
17222281
     });
17232282
     f.block_mut(b_block).insts.push(Inst {
17242283
         id: b_sum,
1725
-        kind: InstKind::IAdd(a_sum, seven),  // folds to const(37)
2284
+        kind: InstKind::IAdd(a_sum, seven), // folds to const(37)
17262285
         ty: IrType::Int(IntWidth::I32),
17272286
         span: dummy_span(),
17282287
     });
@@ -1762,13 +2321,17 @@ fn audit_const_fold_inner_fixpoint_across_vec_order() {
17622321
     // The fold MUST converge in a single `ConstFold.run()` call —
17632322
     // the terminator's value should now define ConstInt(37) (= 10+20+7).
17642323
     let f = &m.functions[0];
1765
-    let terminator_val = f.blocks.iter()
2324
+    let terminator_val = f
2325
+        .blocks
2326
+        .iter()
17662327
         .find_map(|blk| match &blk.terminator {
17672328
             Some(Terminator::Return(Some(v))) => Some(*v),
17682329
             _ => None,
17692330
         })
17702331
         .expect("no Return terminator");
1771
-    let term_kind = f.blocks.iter()
2332
+    let term_kind = f
2333
+        .blocks
2334
+        .iter()
17722335
         .flat_map(|b| b.insts.iter())
17732336
         .find(|i| i.id == terminator_val)
17742337
         .map(|i| i.kind.clone())
@@ -1793,15 +2356,27 @@ fn audit_const_fold_inner_fixpoint_across_vec_order() {
17932356
 fn audit_const_fold_shl_full_width_wrap() {
17942357
     let mut m = Module::new("t".into());
17952358
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
1796
-    let v = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1797
-    let cnt = push(&mut f, InstKind::ConstInt(31, IntWidth::I32), IrType::Int(IntWidth::I32));
2359
+    let v = push(
2360
+        &mut f,
2361
+        InstKind::ConstInt(1, IntWidth::I32),
2362
+        IrType::Int(IntWidth::I32),
2363
+    );
2364
+    let cnt = push(
2365
+        &mut f,
2366
+        InstKind::ConstInt(31, IntWidth::I32),
2367
+        IrType::Int(IntWidth::I32),
2368
+    );
17982369
     let s = push(&mut f, InstKind::Shl(v, cnt), IrType::Int(IntWidth::I32));
17992370
     let entry = f.entry;
18002371
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
18012372
     m.add_function(f);
18022373
 
18032374
     ConstFold.run(&mut m);
1804
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
2375
+    let folded = m.functions[0].blocks[0]
2376
+        .insts
2377
+        .iter()
2378
+        .find(|i| i.id == s)
2379
+        .unwrap();
18052380
     match folded.kind {
18062381
         InstKind::ConstInt(v, IntWidth::I32) => {
18072382
             // 1 << 31 in i32 is INT_MIN = -2147483648.
@@ -1818,15 +2393,27 @@ fn audit_const_fold_shl_full_width_wrap() {
18182393
 fn audit_const_fold_iadd_i16_overflow() {
18192394
     let mut m = Module::new("t".into());
18202395
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I16));
1821
-    let a = push(&mut f, InstKind::ConstInt(32000, IntWidth::I16), IrType::Int(IntWidth::I16));
1822
-    let b = push(&mut f, InstKind::ConstInt(1000,  IntWidth::I16), IrType::Int(IntWidth::I16));
2396
+    let a = push(
2397
+        &mut f,
2398
+        InstKind::ConstInt(32000, IntWidth::I16),
2399
+        IrType::Int(IntWidth::I16),
2400
+    );
2401
+    let b = push(
2402
+        &mut f,
2403
+        InstKind::ConstInt(1000, IntWidth::I16),
2404
+        IrType::Int(IntWidth::I16),
2405
+    );
18232406
     let s = push(&mut f, InstKind::IAdd(a, b), IrType::Int(IntWidth::I16));
18242407
     let entry = f.entry;
18252408
     f.block_mut(entry).terminator = Some(Terminator::Return(Some(s)));
18262409
     m.add_function(f);
18272410
 
18282411
     ConstFold.run(&mut m);
1829
-    let folded = m.functions[0].blocks[0].insts.iter().find(|i| i.id == s).unwrap();
2412
+    let folded = m.functions[0].blocks[0]
2413
+        .insts
2414
+        .iter()
2415
+        .find(|i| i.id == s)
2416
+        .unwrap();
18302417
     match folded.kind {
18312418
         InstKind::ConstInt(v, IntWidth::I16) => {
18322419
             // 32000 + 1000 = 33000, wraps in i16 to -32536
@@ -1850,14 +2437,25 @@ fn audit_const_prop_merge_after_drop() {
18502437
     let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
18512438
 
18522439
     let cond = push(&mut f, InstKind::ConstBool(true), IrType::Bool);
1853
-    let v_a = push(&mut f, InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32));
1854
-    let v_b = push(&mut f, InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32));
2440
+    let v_a = push(
2441
+        &mut f,
2442
+        InstKind::ConstInt(10, IntWidth::I32),
2443
+        IrType::Int(IntWidth::I32),
2444
+    );
2445
+    let v_b = push(
2446
+        &mut f,
2447
+        InstKind::ConstInt(20, IntWidth::I32),
2448
+        IrType::Int(IntWidth::I32),
2449
+    );
18552450
 
18562451
     let a = f.create_block("a");
18572452
     let b = f.create_block("b");
18582453
     let merge = f.create_block("merge");
18592454
     let m_param = f.next_value_id();
1860
-    f.block_mut(merge).params.push(BlockParam { id: m_param, ty: IrType::Int(IntWidth::I32) });
2455
+    f.block_mut(merge).params.push(BlockParam {
2456
+        id: m_param,
2457
+        ty: IrType::Int(IntWidth::I32),
2458
+    });
18612459
 
18622460
     f.block_mut(a).terminator = Some(Terminator::Branch(merge, vec![v_a]));
18632461
     f.block_mut(b).terminator = Some(Terminator::Branch(merge, vec![v_b]));
@@ -1879,11 +2477,20 @@ fn audit_const_prop_merge_after_drop() {
18792477
     ConstProp.run(&mut m);
18802478
 
18812479
     let post = verify_module(&m);
1882
-    assert!(post.is_empty(),
1883
-        "const_prop produced an invalid module after dropping the false arm: {:?}", post);
2480
+    assert!(
2481
+        post.is_empty(),
2482
+        "const_prop produced an invalid module after dropping the false arm: {:?}",
2483
+        post
2484
+    );
18842485
 
18852486
     // After folding, B should be gone but merge should still exist.
18862487
     let f = &m.functions[0];
1887
-    assert!(!f.blocks.iter().any(|bk| bk.id == b), "block B should be pruned");
1888
-    assert!(f.blocks.iter().any(|bk| bk.id == merge), "merge should remain");
2488
+    assert!(
2489
+        !f.blocks.iter().any(|bk| bk.id == b),
2490
+        "block B should be pruned"
2491
+    );
2492
+    assert!(
2493
+        f.blocks.iter().any(|bk| bk.id == merge),
2494
+        "merge should remain"
2495
+    );
18892496
 }
src/opt/bce.rsmodified
322 lines changed — click to load
@@ -13,20 +13,24 @@
1313
 //! element accesses. This pass removes the checks when the index is
1414
 //! provably safe.
1515
 
16
-use crate::ir::inst::*;
17
-use crate::ir::walk::{find_natural_loops, predecessors};
1816
 use super::loop_utils::{find_preheader, resolve_const_int};
1917
 use super::pass::Pass;
18
+use crate::ir::inst::*;
19
+use crate::ir::walk::{find_natural_loops, predecessors};
2020
 
2121
 pub struct Bce;
2222
 
2323
 impl Pass for Bce {
24
-    fn name(&self) -> &'static str { "bce" }
24
+    fn name(&self) -> &'static str {
25
+        "bce"
26
+    }
2527
 
2628
     fn run(&self, module: &mut Module) -> bool {
2729
         let mut changed = false;
2830
         for func in &mut module.functions {
29
-            if bce_function(func) { changed = true; }
31
+            if bce_function(func) {
32
+                changed = true;
33
+            }
3034
         }
3135
         changed
3236
     }
@@ -53,7 +57,9 @@ fn bce_function(func: &mut Function) -> bool {
5357
         }
5458
     }
5559
 
56
-    if to_remove.is_empty() { return false; }
60
+    if to_remove.is_empty() {
61
+        return false;
62
+    }
5763
 
5864
     // Remove in reverse order to preserve indices.
5965
     to_remove.sort_by(|a, b| b.1.cmp(&a.1));
@@ -86,8 +92,12 @@ fn is_provably_safe(
8692
 
8793
     // Case 2: index is a canonical loop IV, and the loop's closed range
8894
     // stays within the checked bounds.
89
-    let Some(lo_const) = resolve_int_scalar(func, lower) else { return false; };
90
-    let Some(hi_const) = resolve_int_scalar(func, upper) else { return false; };
95
+    let Some(lo_const) = resolve_int_scalar(func, lower) else {
96
+        return false;
97
+    };
98
+    let Some(hi_const) = resolve_int_scalar(func, upper) else {
99
+        return false;
100
+    };
91101
     for lp in loops {
92102
         let Some((range_lo, range_hi)) = loop_index_range(func, lp, preds, index) else {
93103
             continue;
@@ -178,9 +188,7 @@ fn loop_init_const(
178188
 ) -> Option<i64> {
179189
     let preheader = find_preheader(func, lp, preds)?;
180190
     match &func.block(preheader).terminator {
181
-        Some(Terminator::Branch(dest, args))
182
-            if *dest == lp.header && param_idx < args.len() =>
183
-        {
191
+        Some(Terminator::Branch(dest, args)) if *dest == lp.header && param_idx < args.len() => {
184192
             resolve_int_scalar(func, args[param_idx])
185193
         }
186194
         _ => None,
@@ -193,18 +201,15 @@ enum LoopDir {
193201
     Descending,
194202
 }
195203
 
196
-fn loop_bound_const(
197
-    func: &Function,
198
-    header: BlockId,
199
-    index: ValueId,
200
-) -> Option<(i64, LoopDir)> {
204
+fn loop_bound_const(func: &Function, header: BlockId, index: ValueId) -> Option<(i64, LoopDir)> {
201205
     for inst in &func.block(header).insts {
202
-        let InstKind::ICmp(op, lhs, rhs) = &inst.kind else { continue };
206
+        let InstKind::ICmp(op, lhs, rhs) = &inst.kind else {
207
+            continue;
208
+        };
203209
         match op {
204210
             CmpOp::Le => {
205211
                 if *lhs == index {
206
-                    return resolve_int_scalar(func, *rhs)
207
-                        .map(|bound| (bound, LoopDir::Ascending));
212
+                    return resolve_int_scalar(func, *rhs).map(|bound| (bound, LoopDir::Ascending));
208213
                 }
209214
                 if *rhs == index {
210215
                     return resolve_int_scalar(func, *lhs)
@@ -217,8 +222,7 @@ fn loop_bound_const(
217222
                         .map(|bound| (bound, LoopDir::Descending));
218223
                 }
219224
                 if *rhs == index {
220
-                    return resolve_int_scalar(func, *lhs)
221
-                        .map(|bound| (bound, LoopDir::Ascending));
225
+                    return resolve_int_scalar(func, *lhs).map(|bound| (bound, LoopDir::Ascending));
222226
                 }
223227
             }
224228
             _ => {}
@@ -235,8 +239,7 @@ fn loop_step_const(
235239
 ) -> Option<i64> {
236240
     let mut step: Option<i64> = None;
237241
     for &latch in &lp.latches {
238
-        let next =
239
-            edge_arg_value(func.block(latch).terminator.as_ref()?, lp.header, param_idx)?;
242
+        let next = edge_arg_value(func.block(latch).terminator.as_ref()?, lp.header, param_idx)?;
240243
         let latch_step = update_step_const(func, index, next)?;
241244
         if latch_step == 0 {
242245
             return None;
@@ -309,7 +312,9 @@ fn resolve_int_scalar(func: &Function, value: ValueId) -> Option<i64> {
309312
 
310313
 fn strip_int_casts(func: &Function, mut value: ValueId) -> ValueId {
311314
     loop {
312
-        let Some(kind) = find_inst_kind(func, value) else { return value };
315
+        let Some(kind) = find_inst_kind(func, value) else {
316
+            return value;
317
+        };
313318
         match kind {
314319
             InstKind::IntExtend(src, _, _) | InstKind::IntTrunc(src, _) => value = *src,
315320
             _ => return value,
@@ -331,7 +336,7 @@ fn find_inst_kind(func: &Function, value: ValueId) -> Option<&InstKind> {
331336
 #[cfg(test)]
332337
 mod tests {
333338
     use super::*;
334
-    use crate::ir::types::{IrType, IntWidth};
339
+    use crate::ir::types::{IntWidth, IrType};
335340
     use crate::opt::pass::Pass;
336341
 
337342
     #[test]
@@ -358,25 +363,33 @@ mod tests {
358363
         let idx = f.next_value_id();
359364
         f.register_type(idx, IrType::Int(IntWidth::I32));
360365
         f.block_mut(f.entry).insts.push(Inst {
361
-            id: idx, ty: IrType::Int(IntWidth::I32), span,
366
+            id: idx,
367
+            ty: IrType::Int(IntWidth::I32),
368
+            span,
362369
             kind: InstKind::ConstInt(3, IntWidth::I32),
363370
         });
364371
         let lo = f.next_value_id();
365372
         f.register_type(lo, IrType::Int(IntWidth::I32));
366373
         f.block_mut(f.entry).insts.push(Inst {
367
-            id: lo, ty: IrType::Int(IntWidth::I32), span,
374
+            id: lo,
375
+            ty: IrType::Int(IntWidth::I32),
376
+            span,
368377
             kind: InstKind::ConstInt(1, IntWidth::I32),
369378
         });
370379
         let hi = f.next_value_id();
371380
         f.register_type(hi, IrType::Int(IntWidth::I32));
372381
         f.block_mut(f.entry).insts.push(Inst {
373
-            id: hi, ty: IrType::Int(IntWidth::I32), span,
382
+            id: hi,
383
+            ty: IrType::Int(IntWidth::I32),
384
+            span,
374385
             kind: InstKind::ConstInt(10, IntWidth::I32),
375386
         });
376387
         let check = f.next_value_id();
377388
         f.register_type(check, IrType::Void);
378389
         f.block_mut(f.entry).insts.push(Inst {
379
-            id: check, ty: IrType::Void, span,
390
+            id: check,
391
+            ty: IrType::Void,
392
+            span,
380393
             kind: InstKind::RuntimeCall(RuntimeFunc::CheckBounds, vec![idx, lo, hi]),
381394
         });
382395
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -387,7 +400,9 @@ mod tests {
387400
         assert!(changed, "constant 3 in [1,10] should be eliminated");
388401
 
389402
         // Verify the CheckBounds call was removed.
390
-        let has_check = m.functions[0].blocks[0].insts.iter()
403
+        let has_check = m.functions[0].blocks[0]
404
+            .insts
405
+            .iter()
391406
             .any(|i| matches!(i.kind, InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _)));
392407
         assert!(!has_check, "CheckBounds should be removed");
393408
     }
@@ -428,8 +443,14 @@ mod tests {
428443
         f.register_type(iv, IrType::Int(IntWidth::I32));
429444
         let sum = f.next_value_id();
430445
         f.register_type(sum, IrType::Int(IntWidth::I32));
431
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
432
-        f.block_mut(header).params.push(BlockParam { id: sum, ty: IrType::Int(IntWidth::I32) });
446
+        f.block_mut(header).params.push(BlockParam {
447
+            id: iv,
448
+            ty: IrType::Int(IntWidth::I32),
449
+        });
450
+        f.block_mut(header).params.push(BlockParam {
451
+            id: sum,
452
+            ty: IrType::Int(IntWidth::I32),
453
+        });
433454
 
434455
         let bound = f.next_value_id();
435456
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -511,15 +532,20 @@ mod tests {
511532
             span,
512533
             kind: InstKind::IAdd(sum, step),
513534
         });
514
-        f.block_mut(body).terminator =
515
-            Some(Terminator::Branch(header, vec![next_iv, next_sum]));
535
+        f.block_mut(body).terminator = Some(Terminator::Branch(header, vec![next_iv, next_sum]));
516536
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
517537
         m.add_function(f);
518538
 
519539
         let pass = Bce;
520
-        assert!(pass.run(&mut m), "canonical counted-loop bounds check should be removed");
540
+        assert!(
541
+            pass.run(&mut m),
542
+            "canonical counted-loop bounds check should be removed"
543
+        );
521544
         let has_check = m.functions[0].block(body).insts.iter().any(|inst| {
522
-            matches!(inst.kind, InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _))
545
+            matches!(
546
+                inst.kind,
547
+                InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _)
548
+            )
523549
         });
524550
         assert!(!has_check, "loop body should no longer contain CheckBounds");
525551
     }
@@ -560,8 +586,14 @@ mod tests {
560586
         f.register_type(iv, IrType::Int(IntWidth::I32));
561587
         let sum = f.next_value_id();
562588
         f.register_type(sum, IrType::Int(IntWidth::I32));
563
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
564
-        f.block_mut(header).params.push(BlockParam { id: sum, ty: IrType::Int(IntWidth::I32) });
589
+        f.block_mut(header).params.push(BlockParam {
590
+            id: iv,
591
+            ty: IrType::Int(IntWidth::I32),
592
+        });
593
+        f.block_mut(header).params.push(BlockParam {
594
+            id: sum,
595
+            ty: IrType::Int(IntWidth::I32),
596
+        });
565597
 
566598
         let bound = f.next_value_id();
567599
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -643,8 +675,7 @@ mod tests {
643675
             span,
644676
             kind: InstKind::IAdd(sum, step),
645677
         });
646
-        f.block_mut(body).terminator =
647
-            Some(Terminator::Branch(header, vec![next_iv, next_sum]));
678
+        f.block_mut(body).terminator = Some(Terminator::Branch(header, vec![next_iv, next_sum]));
648679
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
649680
         m.add_function(f);
650681
 
@@ -681,7 +712,10 @@ mod tests {
681712
 
682713
         let iv = f.next_value_id();
683714
         f.register_type(iv, IrType::Int(IntWidth::I32));
684
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
715
+        f.block_mut(header).params.push(BlockParam {
716
+            id: iv,
717
+            ty: IrType::Int(IntWidth::I32),
718
+        });
685719
 
686720
         let bound = f.next_value_id();
687721
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -768,9 +802,15 @@ mod tests {
768802
         m.add_function(f);
769803
 
770804
         let pass = Bce;
771
-        assert!(pass.run(&mut m), "iv+1 check should be removed for trip range 2..7 and checked bounds 1..8");
805
+        assert!(
806
+            pass.run(&mut m),
807
+            "iv+1 check should be removed for trip range 2..7 and checked bounds 1..8"
808
+        );
772809
         let has_check = m.functions[0].block(body).insts.iter().any(|inst| {
773
-            matches!(inst.kind, InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _))
810
+            matches!(
811
+                inst.kind,
812
+                InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _)
813
+            )
774814
         });
775815
         assert!(!has_check, "loop body should no longer contain CheckBounds");
776816
     }
@@ -801,7 +841,10 @@ mod tests {
801841
 
802842
         let iv = f.next_value_id();
803843
         f.register_type(iv, IrType::Int(IntWidth::I32));
804
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
844
+        f.block_mut(header).params.push(BlockParam {
845
+            id: iv,
846
+            ty: IrType::Int(IntWidth::I32),
847
+        });
805848
 
806849
         let bound = f.next_value_id();
807850
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -888,9 +931,15 @@ mod tests {
888931
         m.add_function(f);
889932
 
890933
         let pass = Bce;
891
-        assert!(pass.run(&mut m), "iv-1 check should be removed for trip range 2..7 and checked bounds 1..8");
934
+        assert!(
935
+            pass.run(&mut m),
936
+            "iv-1 check should be removed for trip range 2..7 and checked bounds 1..8"
937
+        );
892938
         let has_check = m.functions[0].block(body).insts.iter().any(|inst| {
893
-            matches!(inst.kind, InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _))
939
+            matches!(
940
+                inst.kind,
941
+                InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _)
942
+            )
894943
         });
895944
         assert!(!has_check, "loop body should no longer contain CheckBounds");
896945
     }
@@ -921,7 +970,10 @@ mod tests {
921970
 
922971
         let iv = f.next_value_id();
923972
         f.register_type(iv, IrType::Int(IntWidth::I32));
924
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
973
+        f.block_mut(header).params.push(BlockParam {
974
+            id: iv,
975
+            ty: IrType::Int(IntWidth::I32),
976
+        });
925977
 
926978
         let bound = f.next_value_id();
927979
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -1048,7 +1100,10 @@ mod tests {
10481100
 
10491101
         let iv = f.next_value_id();
10501102
         f.register_type(iv, IrType::Int(IntWidth::I32));
1051
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
1103
+        f.block_mut(header).params.push(BlockParam {
1104
+            id: iv,
1105
+            ty: IrType::Int(IntWidth::I32),
1106
+        });
10521107
 
10531108
         let bound = f.next_value_id();
10541109
         f.register_type(bound, IrType::Int(IntWidth::I32));
@@ -1148,7 +1203,10 @@ mod tests {
11481203
             "iv+5 check should be removed when the trip sequence is only 5 and checked bounds are 1..10"
11491204
         );
11501205
         let has_check = m.functions[0].block(body).insts.iter().any(|inst| {
1151
-            matches!(inst.kind, InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _))
1206
+            matches!(
1207
+                inst.kind,
1208
+                InstKind::RuntimeCall(RuntimeFunc::CheckBounds, _)
1209
+            )
11521210
         });
11531211
         assert!(!has_check, "loop body should no longer contain CheckBounds");
11541212
     }
src/opt/call_resolve.rsmodified
35 lines changed — click to load
@@ -7,18 +7,22 @@
77
 //!
88
 //! Runs as the first pass at O1+ (before Mem2Reg).
99
 
10
-use std::collections::HashMap;
11
-use crate::ir::inst::*;
1210
 use super::pass::Pass;
11
+use crate::ir::inst::*;
12
+use std::collections::HashMap;
1313
 
1414
 pub struct CallResolve;
1515
 
1616
 impl Pass for CallResolve {
17
-    fn name(&self) -> &'static str { "call-resolve" }
17
+    fn name(&self) -> &'static str {
18
+        "call-resolve"
19
+    }
1820
 
1921
     fn run(&self, module: &mut Module) -> bool {
2022
         // Build name → index mapping for all functions in the module.
21
-        let name_to_idx: HashMap<String, u32> = module.functions.iter()
23
+        let name_to_idx: HashMap<String, u32> = module
24
+            .functions
25
+            .iter()
2226
             .enumerate()
2327
             .map(|(i, f)| (f.name.clone(), i as u32))
2428
             .collect();
@@ -47,8 +51,8 @@ impl Pass for CallResolve {
4751
 #[cfg(test)]
4852
 mod tests {
4953
     use super::*;
50
-    use crate::ir::types::{IrType, IntWidth};
5154
     use crate::ir::inst::*;
55
+    use crate::ir::types::{IntWidth, IrType};
5256
     use crate::opt::pass::Pass;
5357
 
5458
     #[test]
src/opt/callgraph.rsmodified
112 lines changed — click to load
@@ -4,9 +4,9 @@
44
 //! Detects recursive functions via DFS cycle detection. Provides
55
 //! reverse post-order iteration for bottom-up inlining (callees first).
66
 
7
-use std::collections::HashSet;
87
 use crate::ir::inst::*;
98
 use crate::ir::walk::find_natural_loops;
9
+use std::collections::HashSet;
1010
 
1111
 /// A node in the call graph — one per function in the module.
1212
 #[derive(Debug)]
@@ -33,13 +33,15 @@ impl CallGraph {
3333
     /// Build the call graph from a module.
3434
     pub fn build(module: &Module) -> Self {
3535
         let n = module.functions.len();
36
-        let mut nodes: Vec<CallNode> = (0..n).map(|i| CallNode {
37
-            func_idx: i as u32,
38
-            callees: Vec::new(),
39
-            callers: Vec::new(),
40
-            inst_count: 0,
41
-            is_recursive: false,
42
-        }).collect();
36
+        let mut nodes: Vec<CallNode> = (0..n)
37
+            .map(|i| CallNode {
38
+                func_idx: i as u32,
39
+                callees: Vec::new(),
40
+                callers: Vec::new(),
41
+                inst_count: 0,
42
+                is_recursive: false,
43
+            })
44
+            .collect();
4345
 
4446
         // Scan each function for Call(Internal) instructions.
4547
         for (i, func) in module.functions.iter().enumerate() {
@@ -122,7 +124,9 @@ impl CallGraph {
122124
 }
123125
 
124126
 fn rpo_dfs(nodes: &[CallNode], idx: u32, visited: &mut [bool], order: &mut Vec<u32>) {
125
-    if visited[idx as usize] { return; }
127
+    if visited[idx as usize] {
128
+        return;
129
+    }
126130
     visited[idx as usize] = true;
127131
     for &callee in &nodes[idx as usize].callees {
128132
         if (callee as usize) < nodes.len() {
@@ -154,12 +158,16 @@ fn dfs_cycle(nodes: &[CallNode], idx: u32, visiting: &mut HashSet<u32>) -> bool
154158
 #[cfg(test)]
155159
 mod tests {
156160
     use super::*;
157
-    use crate::ir::types::{IrType, IntWidth};
158
-    use crate::lexer::{Span, Position};
161
+    use crate::ir::types::{IntWidth, IrType};
162
+    use crate::lexer::{Position, Span};
159163
 
160164
     fn span() -> Span {
161165
         let pos = Position { line: 0, col: 0 };
162
-        Span { file_id: 0, start: pos, end: pos }
166
+        Span {
167
+            file_id: 0,
168
+            start: pos,
169
+            end: pos,
170
+        }
163171
     }
164172
 
165173
     #[test]
@@ -170,14 +178,19 @@ mod tests {
170178
         let call_id = f.next_value_id();
171179
         f.register_type(call_id, IrType::Int(IntWidth::I32));
172180
         f.block_mut(f.entry).insts.push(Inst {
173
-            id: call_id, ty: IrType::Int(IntWidth::I32), span: span(),
181
+            id: call_id,
182
+            ty: IrType::Int(IntWidth::I32),
183
+            span: span(),
174184
             kind: InstKind::Call(FuncRef::Internal(0), vec![]),
175185
         });
176186
         f.block_mut(f.entry).terminator = Some(Terminator::Return(Some(call_id)));
177187
         m.add_function(f);
178188
 
179189
         let cg = CallGraph::build(&m);
180
-        assert!(cg.is_recursive(0), "self-calling function should be recursive");
190
+        assert!(
191
+            cg.is_recursive(0),
192
+            "self-calling function should be recursive"
193
+        );
181194
     }
182195
 
183196
     #[test]
@@ -193,7 +206,9 @@ mod tests {
193206
         let call_id = caller.next_value_id();
194207
         caller.register_type(call_id, IrType::Int(IntWidth::I32));
195208
         caller.block_mut(caller.entry).insts.push(Inst {
196
-            id: call_id, ty: IrType::Int(IntWidth::I32), span: span(),
209
+            id: call_id,
210
+            ty: IrType::Int(IntWidth::I32),
211
+            span: span(),
197212
             kind: InstKind::Call(FuncRef::Internal(0), vec![]),
198213
         });
199214
         caller.block_mut(caller.entry).terminator = Some(Terminator::Return(None));
@@ -218,7 +233,9 @@ mod tests {
218233
         let cid = caller.next_value_id();
219234
         caller.register_type(cid, IrType::Void);
220235
         caller.block_mut(caller.entry).insts.push(Inst {
221
-            id: cid, ty: IrType::Void, span: span(),
236
+            id: cid,
237
+            ty: IrType::Void,
238
+            span: span(),
222239
             kind: InstKind::Call(FuncRef::Internal(0), vec![]),
223240
         });
224241
         caller.block_mut(caller.entry).terminator = Some(Terminator::Return(None));
@@ -229,6 +246,9 @@ mod tests {
229246
         // Callee should come before caller in RPO.
230247
         let callee_pos = rpo.iter().position(|&i| i == 0).unwrap();
231248
         let caller_pos = rpo.iter().position(|&i| i == 1).unwrap();
232
-        assert!(callee_pos < caller_pos, "callee should come before caller in RPO");
249
+        assert!(
250
+            callee_pos < caller_pos,
251
+            "callee should come before caller in RPO"
252
+        );
233253
     }
234254
 }
src/opt/const_arg.rsmodified
167 lines changed — click to load
@@ -16,13 +16,20 @@ use super::util::substitute_uses;
1616
 pub struct ConstArgSpecialize;
1717
 
1818
 impl Pass for ConstArgSpecialize {
19
-    fn name(&self) -> &'static str { "const-arg-specialize" }
19
+    fn name(&self) -> &'static str {
20
+        "const-arg-specialize"
21
+    }
2022
 
2123
     fn run(&self, module: &mut Module) -> bool {
2224
         let param_modes: Vec<Vec<Option<ParamMode>>> = module
2325
             .functions
2426
             .iter()
25
-            .map(|func| func.params.iter().map(|param| classify_param(func, param)).collect())
27
+            .map(|func| {
28
+                func.params
29
+                    .iter()
30
+                    .map(|param| classify_param(func, param))
31
+                    .collect()
32
+            })
2633
             .collect();
2734
 
2835
         let plans = specialization_plans(module, &param_modes);
@@ -309,7 +316,11 @@ fn default_span(func: &Function) -> Span {
309316
         span
310317
     } else {
311318
         let pos = Position { line: 0, col: 0 };
312
-        Span { file_id: 0, start: pos, end: pos }
319
+        Span {
320
+            file_id: 0,
321
+            start: pos,
322
+            end: pos,
323
+        }
313324
     }
314325
 }
315326
 
@@ -372,18 +383,27 @@ fn apply_plan(module: &mut Module, plan: SpecializationPlan) {
372383
 mod tests {
373384
     use super::*;
374385
     use crate::ir::types::IrType;
375
-    use crate::opt::dead_arg::DeadArgElim;
376386
     use crate::lexer::{Position, Span};
387
+    use crate::opt::dead_arg::DeadArgElim;
377388
 
378389
     fn span() -> Span {
379390
         let pos = Position { line: 0, col: 0 };
380
-        Span { file_id: 0, start: pos, end: pos }
391
+        Span {
392
+            file_id: 0,
393
+            start: pos,
394
+            end: pos,
395
+        }
381396
     }
382397
 
383398
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
384399
         let id = f.next_value_id();
385400
         let entry = f.entry;
386
-        f.block_mut(entry).insts.push(Inst { id, kind, ty: ty.clone(), span: span() });
401
+        f.block_mut(entry).insts.push(Inst {
402
+            id,
403
+            kind,
404
+            ty: ty.clone(),
405
+            span: span(),
406
+        });
387407
         f.register_type(id, ty);
388408
         id
389409
     }
@@ -418,21 +438,41 @@ mod tests {
418438
         module.add_function(callee);
419439
 
420440
         let mut caller = Function::new("main".into(), vec![], IrType::Int(IntWidth::I32));
421
-        let x1 = push(&mut caller, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
422
-        let step1 = push(&mut caller, InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
441
+        let x1 = push(
442
+            &mut caller,
443
+            InstKind::ConstInt(7, IntWidth::I32),
444
+            IrType::Int(IntWidth::I32),
445
+        );
446
+        let step1 = push(
447
+            &mut caller,
448
+            InstKind::ConstInt(3, IntWidth::I32),
449
+            IrType::Int(IntWidth::I32),
450
+        );
423451
         let c1 = push(
424452
             &mut caller,
425453
             InstKind::Call(FuncRef::Internal(0), vec![x1, step1]),
426454
             IrType::Int(IntWidth::I32),
427455
         );
428
-        let x2 = push(&mut caller, InstKind::ConstInt(9, IntWidth::I32), IrType::Int(IntWidth::I32));
429
-        let step2 = push(&mut caller, InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
456
+        let x2 = push(
457
+            &mut caller,
458
+            InstKind::ConstInt(9, IntWidth::I32),
459
+            IrType::Int(IntWidth::I32),
460
+        );
461
+        let step2 = push(
462
+            &mut caller,
463
+            InstKind::ConstInt(3, IntWidth::I32),
464
+            IrType::Int(IntWidth::I32),
465
+        );
430466
         let c2 = push(
431467
             &mut caller,
432468
             InstKind::Call(FuncRef::Internal(0), vec![x2, step2]),
433469
             IrType::Int(IntWidth::I32),
434470
         );
435
-        let total = push(&mut caller, InstKind::IAdd(c1, c2), IrType::Int(IntWidth::I32));
471
+        let total = push(
472
+            &mut caller,
473
+            InstKind::IAdd(c1, c2),
474
+            IrType::Int(IntWidth::I32),
475
+        );
436476
         let caller_entry = caller.entry;
437477
         caller.block_mut(caller_entry).terminator = Some(Terminator::Return(Some(total)));
438478
         module.add_function(caller);
@@ -440,12 +480,20 @@ mod tests {
440480
         assert!(ConstArgSpecialize.run(&mut module));
441481
         assert!(DeadArgElim.run(&mut module));
442482
 
443
-        assert_eq!(module.functions[0].params.len(), 1, "specialized helper should drop constant dummy");
483
+        assert_eq!(
484
+            module.functions[0].params.len(),
485
+            1,
486
+            "specialized helper should drop constant dummy"
487
+        );
444488
         let call_args_1 = match &module.functions[1].blocks[0].insts[2].kind {
445489
             InstKind::Call(FuncRef::Internal(0), args) => args,
446490
             other => panic!("expected call, got {:?}", other),
447491
         };
448
-        assert_eq!(call_args_1.len(), 1, "call site should drop specialized constant arg");
492
+        assert_eq!(
493
+            call_args_1.len(),
494
+            1,
495
+            "call site should drop specialized constant arg"
496
+        );
449497
     }
450498
 
451499
     #[test]
@@ -478,15 +526,31 @@ mod tests {
478526
         module.add_function(callee);
479527
 
480528
         let mut caller = Function::new("main".into(), vec![], IrType::Int(IntWidth::I32));
481
-        let x1 = push(&mut caller, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
482
-        let step1 = push(&mut caller, InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
529
+        let x1 = push(
530
+            &mut caller,
531
+            InstKind::ConstInt(7, IntWidth::I32),
532
+            IrType::Int(IntWidth::I32),
533
+        );
534
+        let step1 = push(
535
+            &mut caller,
536
+            InstKind::ConstInt(3, IntWidth::I32),
537
+            IrType::Int(IntWidth::I32),
538
+        );
483539
         let _ = push(
484540
             &mut caller,
485541
             InstKind::Call(FuncRef::Internal(0), vec![x1, step1]),
486542
             IrType::Int(IntWidth::I32),
487543
         );
488
-        let x2 = push(&mut caller, InstKind::ConstInt(9, IntWidth::I32), IrType::Int(IntWidth::I32));
489
-        let step2 = push(&mut caller, InstKind::ConstInt(4, IntWidth::I32), IrType::Int(IntWidth::I32));
544
+        let x2 = push(
545
+            &mut caller,
546
+            InstKind::ConstInt(9, IntWidth::I32),
547
+            IrType::Int(IntWidth::I32),
548
+        );
549
+        let step2 = push(
550
+            &mut caller,
551
+            InstKind::ConstInt(4, IntWidth::I32),
552
+            IrType::Int(IntWidth::I32),
553
+        );
490554
         let call = push(
491555
             &mut caller,
492556
             InstKind::Call(FuncRef::Internal(0), vec![x2, step2]),
src/opt/const_fold.rsmodified
506 lines changed — click to load
@@ -27,7 +27,7 @@
2727
 
2828
 use super::pass::Pass;
2929
 use crate::ir::inst::*;
30
-use crate::ir::types::{IrType, IntWidth, FloatWidth};
30
+use crate::ir::types::{FloatWidth, IntWidth, IrType};
3131
 use std::collections::HashMap;
3232
 
3333
 /// Compile-time constant value, normalized for folding.
@@ -56,12 +56,8 @@ impl Const {
5656
     ///    the producer-side guarantee from M-1.
5757
     fn from_inst(kind: &InstKind) -> Option<Self> {
5858
         match kind {
59
-            InstKind::ConstInt(v, w) => {
60
-                Some(Const::Int(sext(*v, w.bits()), *w))
61
-            }
62
-            InstKind::ConstFloat(v, w) => {
63
-                Some(Const::Float(round_for_width(*v, *w), *w))
64
-            }
59
+            InstKind::ConstInt(v, w) => Some(Const::Int(sext(*v, w.bits()), *w)),
60
+            InstKind::ConstFloat(v, w) => Some(Const::Float(round_for_width(*v, *w), *w)),
6561
             InstKind::ConstBool(b) => Some(Const::Bool(*b)),
6662
             _ => None,
6763
         }
@@ -71,8 +67,9 @@ impl Const {
7167
 /// Sign-extend `v` from `bits` to a full i128. Used so that comparisons
7268
 /// and arithmetic on narrower integer types match hardware behavior.
7369
 fn sext(v: i128, bits: u32) -> i128 {
74
-    if bits >= 128 { v }
75
-    else {
70
+    if bits >= 128 {
71
+        v
72
+    } else {
7673
         let shift = 128 - bits;
7774
         (v << shift) >> shift
7875
     }
@@ -81,8 +78,11 @@ fn sext(v: i128, bits: u32) -> i128 {
8178
 /// Mask `v` down to `bits` low bits. The IR stores integers as i128 but
8279
 /// arithmetic must wrap at the declared width.
8380
 fn mask(v: i128, bits: u32) -> i128 {
84
-    if bits >= 128 { v }
85
-    else { v & ((1i128 << bits) - 1) }
81
+    if bits >= 128 {
82
+        v
83
+    } else {
84
+        v & ((1i128 << bits) - 1)
85
+    }
8686
 }
8787
 
8888
 /// Truncate-then-sign-extend a wide arithmetic result back to its
@@ -149,8 +149,12 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
149149
         InstKind::IDiv(a, b) => {
150150
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
151151
                 if let IrType::Int(w) = ty {
152
-                    if bv == 0 { return None; } // leave divide-by-zero to runtime
153
-                    if av == signed_min(*w) && bv == -1 { return None; }
152
+                    if bv == 0 {
153
+                        return None;
154
+                    } // leave divide-by-zero to runtime
155
+                    if av == signed_min(*w) && bv == -1 {
156
+                        return None;
157
+                    }
154158
                     return Some(InstKind::ConstInt(norm(av / bv, *w), *w));
155159
                 }
156160
             }
@@ -159,8 +163,12 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
159163
         InstKind::IMod(a, b) => {
160164
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
161165
                 if let IrType::Int(w) = ty {
162
-                    if bv == 0 { return None; }
163
-                    if av == signed_min(*w) && bv == -1 { return None; }
166
+                    if bv == 0 {
167
+                        return None;
168
+                    }
169
+                    if av == signed_min(*w) && bv == -1 {
170
+                        return None;
171
+                    }
164172
                     return Some(InstKind::ConstInt(norm(av % bv, *w), *w));
165173
                 }
166174
             }
@@ -255,7 +263,7 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
255263
 
256264
         // Bitwise ---------------------------------------------------------
257265
         InstKind::BitAnd(a, b) => fold_int_bin(get(a), get(b), ty, |x, y| x & y),
258
-        InstKind::BitOr(a, b)  => fold_int_bin(get(a), get(b), ty, |x, y| x | y),
266
+        InstKind::BitOr(a, b) => fold_int_bin(get(a), get(b), ty, |x, y| x | y),
259267
         InstKind::BitXor(a, b) => fold_int_bin(get(a), get(b), ty, |x, y| x ^ y),
260268
         InstKind::BitNot(a) => {
261269
             if let Some(Const::Int(av, _)) = get(a) {
@@ -278,10 +286,7 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
278286
                 if let IrType::Int(w) = ty {
279287
                     let bits = w.bits() as i128;
280288
                     if (0..bits).contains(&bv) {
281
-                        return Some(InstKind::ConstInt(
282
-                            norm(av.wrapping_shl(bv as u32), *w),
283
-                            *w,
284
-                        ));
289
+                        return Some(InstKind::ConstInt(norm(av.wrapping_shl(bv as u32), *w), *w));
285290
                     }
286291
                     return None;
287292
                 }
@@ -324,7 +329,10 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
324329
         InstKind::PopCount(a) => {
325330
             if let (Some(Const::Int(av, src_w)), IrType::Int(out_w)) = (get(a), ty) {
326331
                 let val = mask(av, src_w.bits()) as u128;
327
-                return Some(InstKind::ConstInt(norm(val.count_ones() as i128, *out_w), *out_w));
332
+                return Some(InstKind::ConstInt(
333
+                    norm(val.count_ones() as i128, *out_w),
334
+                    *out_w,
335
+                ));
328336
             }
329337
             None
330338
         }
@@ -345,7 +353,11 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
345353
             if let (Some(Const::Int(av, src_w)), IrType::Int(out_w)) = (get(a), ty) {
346354
                 let bits = src_w.bits();
347355
                 let val = mask(av, bits) as u128;
348
-                let tz = if val == 0 { bits as i128 } else { val.trailing_zeros() as i128 };
356
+                let tz = if val == 0 {
357
+                    bits as i128
358
+                } else {
359
+                    val.trailing_zeros() as i128
360
+                };
349361
                 return Some(InstKind::ConstInt(norm(tz, *out_w), *out_w));
350362
             }
351363
             None
@@ -377,7 +389,9 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
377389
         }
378390
         InstKind::FloatToInt(a, w) => {
379391
             if let Some(Const::Float(av, src_fw)) = get(a) {
380
-                if av.is_nan() || av.is_infinite() { return None; }
392
+                if av.is_nan() || av.is_infinite() {
393
+                    return None;
394
+                }
381395
                 // Audit B-3 (defense in depth): re-round at the
382396
                 // source float width before truncating. The M-1
383397
                 // invariant says any f32-tagged Const::Float is
@@ -388,20 +402,22 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
388402
                 // Fortran INT() truncates toward zero. Match.
389403
                 let truncd = av.trunc();
390404
                 let lo = match w {
391
-                    IntWidth::I8  => i8::MIN  as f64,
405
+                    IntWidth::I8 => i8::MIN as f64,
392406
                     IntWidth::I16 => i16::MIN as f64,
393407
                     IntWidth::I32 => i32::MIN as f64,
394408
                     IntWidth::I64 => i64::MIN as f64,
395409
                     IntWidth::I128 => return None,
396410
                 };
397411
                 let hi = match w {
398
-                    IntWidth::I8  => i8::MAX  as f64,
412
+                    IntWidth::I8 => i8::MAX as f64,
399413
                     IntWidth::I16 => i16::MAX as f64,
400414
                     IntWidth::I32 => i32::MAX as f64,
401415
                     IntWidth::I64 => i64::MAX as f64,
402416
                     IntWidth::I128 => return None,
403417
                 };
404
-                if truncd < lo || truncd > hi { return None; }
418
+                if truncd < lo || truncd > hi {
419
+                    return None;
420
+                }
405421
                 return Some(InstKind::ConstInt(norm(truncd as i128, *w), *w));
406422
             }
407423
             None
@@ -418,7 +434,11 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
418434
         }
419435
         InstKind::IntExtend(a, w, signed) => {
420436
             if let Some(Const::Int(av, src_w)) = get(a) {
421
-                let v = if *signed { sext(av, src_w.bits()) } else { mask(av, src_w.bits()) };
437
+                let v = if *signed {
438
+                    sext(av, src_w.bits())
439
+                } else {
440
+                    mask(av, src_w.bits())
441
+                };
422442
                 return Some(InstKind::ConstInt(norm(v, *w), *w));
423443
             }
424444
             None
@@ -467,9 +487,7 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
467487
                         (IrType::Float(FloatWidth::F64), Const::Float(v, _)) => {
468488
                             Some(InstKind::ConstFloat(v, FloatWidth::F64))
469489
                         }
470
-                        (IrType::Bool, Const::Bool(b)) => {
471
-                            Some(InstKind::ConstBool(b))
472
-                        }
490
+                        (IrType::Bool, Const::Bool(b)) => Some(InstKind::ConstBool(b)),
473491
                         // Type categories disagree — bail rather than
474492
                         // type-pun. The verifier doesn't catch the
475493
                         // mismatch (it only checks `is_int`/`is_float`
@@ -496,7 +514,8 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
496514
 // f32 destinations because the op itself can produce a value
497515
 // outside f32's representable range.
498516
 fn fold_float_bin<F>(a: Option<Const>, b: Option<Const>, ty: &IrType, op: F) -> Option<InstKind>
499
-where F: FnOnce(f64, f64) -> f64
517
+where
518
+    F: FnOnce(f64, f64) -> f64,
500519
 {
501520
     if let (Some(Const::Float(av, _)), Some(Const::Float(bv, _))) = (a, b) {
502521
         if let IrType::Float(w) = ty {
@@ -509,7 +528,8 @@ where F: FnOnce(f64, f64) -> f64
509528
 }
510529
 
511530
 fn fold_float_un<F>(a: Option<Const>, ty: &IrType, op: F) -> Option<InstKind>
512
-where F: FnOnce(f64) -> f64
531
+where
532
+    F: FnOnce(f64) -> f64,
513533
 {
514534
     if let Some(Const::Float(av, _)) = a {
515535
         if let IrType::Float(w) = ty {
@@ -522,7 +542,8 @@ where F: FnOnce(f64) -> f64
522542
 }
523543
 
524544
 fn fold_int_bin<F>(a: Option<Const>, b: Option<Const>, ty: &IrType, op: F) -> Option<InstKind>
525
-where F: FnOnce(i128, i128) -> i128
545
+where
546
+    F: FnOnce(i128, i128) -> i128,
526547
 {
527548
     if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (a, b) {
528549
         if let IrType::Int(w) = ty {
@@ -536,7 +557,9 @@ where F: FnOnce(i128, i128) -> i128
536557
 pub struct ConstFold;
537558
 
538559
 impl Pass for ConstFold {
539
-    fn name(&self) -> &'static str { "const-fold" }
560
+    fn name(&self) -> &'static str {
561
+        "const-fold"
562
+    }
540563
 
541564
     fn run(&self, module: &mut Module) -> bool {
542565
         let mut changed = false;
@@ -573,7 +596,9 @@ impl Pass for ConstFold {
573596
                 inner_changed = false;
574597
                 for block in &mut func.blocks {
575598
                     for inst in &mut block.insts {
576
-                        if consts.contains_key(&inst.id) { continue; }
599
+                        if consts.contains_key(&inst.id) {
600
+                            continue;
601
+                        }
577602
                         if let Some(new_kind) = try_fold(&inst.kind, &inst.ty, &consts) {
578603
                             if let Some(c) = Const::from_inst(&new_kind) {
579604
                                 consts.insert(inst.id, c);
@@ -597,7 +622,11 @@ mod tests {
597622
 
598623
     fn dummy_span() -> crate::lexer::Span {
599624
         let p = crate::lexer::Position { line: 1, col: 1 };
600
-        crate::lexer::Span { start: p, end: p, file_id: 0 }
625
+        crate::lexer::Span {
626
+            start: p,
627
+            end: p,
628
+            file_id: 0,
629
+        }
601630
     }
602631
 
603632
     fn make_module_with(insts: Vec<(InstKind, IrType)>) -> (Module, Vec<ValueId>) {
@@ -608,7 +637,12 @@ mod tests {
608637
         for (kind, ty) in insts {
609638
             let id = f.next_value_id();
610639
             ids.push(id);
611
-            f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
640
+            f.block_mut(entry).insts.push(Inst {
641
+                id,
642
+                kind,
643
+                ty,
644
+                span: dummy_span(),
645
+            });
612646
         }
613647
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
614648
         m.add_function(f);
@@ -616,15 +650,28 @@ mod tests {
616650
     }
617651
 
618652
     fn first_block_kinds(m: &Module) -> Vec<InstKind> {
619
-        m.functions[0].blocks[0].insts.iter().map(|i| i.kind.clone()).collect()
653
+        m.functions[0].blocks[0]
654
+            .insts
655
+            .iter()
656
+            .map(|i| i.kind.clone())
657
+            .collect()
620658
     }
621659
 
622660
     #[test]
623661
     fn folds_iadd_i32() {
624662
         let (mut m, ids) = make_module_with(vec![
625
-            (InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32)),
626
-            (InstKind::ConstInt(4, IntWidth::I32), IrType::Int(IntWidth::I32)),
627
-            (InstKind::IAdd(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I32)),
663
+            (
664
+                InstKind::ConstInt(3, IntWidth::I32),
665
+                IrType::Int(IntWidth::I32),
666
+            ),
667
+            (
668
+                InstKind::ConstInt(4, IntWidth::I32),
669
+                IrType::Int(IntWidth::I32),
670
+            ),
671
+            (
672
+                InstKind::IAdd(ValueId(0), ValueId(1)),
673
+                IrType::Int(IntWidth::I32),
674
+            ),
628675
         ]);
629676
         let _ = ids;
630677
         assert!(ConstFold.run(&mut m));
@@ -636,9 +683,18 @@ mod tests {
636683
     fn integer_overflow_wraps_at_width() {
637684
         // i8: 100 + 50 = 150 → wraps to -106
638685
         let (mut m, _) = make_module_with(vec![
639
-            (InstKind::ConstInt(100, IntWidth::I8), IrType::Int(IntWidth::I8)),
640
-            (InstKind::ConstInt(50,  IntWidth::I8), IrType::Int(IntWidth::I8)),
641
-            (InstKind::IAdd(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I8)),
686
+            (
687
+                InstKind::ConstInt(100, IntWidth::I8),
688
+                IrType::Int(IntWidth::I8),
689
+            ),
690
+            (
691
+                InstKind::ConstInt(50, IntWidth::I8),
692
+                IrType::Int(IntWidth::I8),
693
+            ),
694
+            (
695
+                InstKind::IAdd(ValueId(0), ValueId(1)),
696
+                IrType::Int(IntWidth::I8),
697
+            ),
642698
         ]);
643699
         assert!(ConstFold.run(&mut m));
644700
         let kinds = first_block_kinds(&m);
@@ -651,9 +707,18 @@ mod tests {
651707
     #[test]
652708
     fn idiv_by_zero_left_alone() {
653709
         let (mut m, _) = make_module_with(vec![
654
-            (InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32)),
655
-            (InstKind::ConstInt(0,  IntWidth::I32), IrType::Int(IntWidth::I32)),
656
-            (InstKind::IDiv(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I32)),
710
+            (
711
+                InstKind::ConstInt(10, IntWidth::I32),
712
+                IrType::Int(IntWidth::I32),
713
+            ),
714
+            (
715
+                InstKind::ConstInt(0, IntWidth::I32),
716
+                IrType::Int(IntWidth::I32),
717
+            ),
718
+            (
719
+                InstKind::IDiv(ValueId(0), ValueId(1)),
720
+                IrType::Int(IntWidth::I32),
721
+            ),
657722
         ]);
658723
         assert!(!ConstFold.run(&mut m));
659724
         let kinds = first_block_kinds(&m);
@@ -663,9 +728,18 @@ mod tests {
663728
     #[test]
664729
     fn fmul_f64() {
665730
         let (mut m, _) = make_module_with(vec![
666
-            (InstKind::ConstFloat(2.0, FloatWidth::F64), IrType::Float(FloatWidth::F64)),
667
-            (InstKind::ConstFloat(3.14, FloatWidth::F64), IrType::Float(FloatWidth::F64)),
668
-            (InstKind::FMul(ValueId(0), ValueId(1)), IrType::Float(FloatWidth::F64)),
731
+            (
732
+                InstKind::ConstFloat(2.0, FloatWidth::F64),
733
+                IrType::Float(FloatWidth::F64),
734
+            ),
735
+            (
736
+                InstKind::ConstFloat(3.14, FloatWidth::F64),
737
+                IrType::Float(FloatWidth::F64),
738
+            ),
739
+            (
740
+                InstKind::FMul(ValueId(0), ValueId(1)),
741
+                IrType::Float(FloatWidth::F64),
742
+            ),
669743
         ]);
670744
         assert!(ConstFold.run(&mut m));
671745
         let kinds = first_block_kinds(&m);
@@ -678,12 +752,24 @@ mod tests {
678752
     #[test]
679753
     fn icmp_eq_true() {
680754
         let (mut m, _) = make_module_with(vec![
681
-            (InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32)),
682
-            (InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32)),
683
-            (InstKind::ICmp(CmpOp::Eq, ValueId(0), ValueId(1)), IrType::Bool),
755
+            (
756
+                InstKind::ConstInt(5, IntWidth::I32),
757
+                IrType::Int(IntWidth::I32),
758
+            ),
759
+            (
760
+                InstKind::ConstInt(5, IntWidth::I32),
761
+                IrType::Int(IntWidth::I32),
762
+            ),
763
+            (
764
+                InstKind::ICmp(CmpOp::Eq, ValueId(0), ValueId(1)),
765
+                IrType::Bool,
766
+            ),
684767
         ]);
685768
         assert!(ConstFold.run(&mut m));
686
-        assert!(matches!(first_block_kinds(&m)[2], InstKind::ConstBool(true)));
769
+        assert!(matches!(
770
+            first_block_kinds(&m)[2],
771
+            InstKind::ConstBool(true)
772
+        ));
687773
     }
688774
 
689775
     #[test]
@@ -691,20 +777,41 @@ mod tests {
691777
         // i8 representation: -1 stored as 0xff (255). Without sign-extension,
692778
         // a naive (av < bv) would compare 255 < 1 → false; correct is true.
693779
         let (mut m, _) = make_module_with(vec![
694
-            (InstKind::ConstInt(-1, IntWidth::I8), IrType::Int(IntWidth::I8)),
695
-            (InstKind::ConstInt(1,  IntWidth::I8), IrType::Int(IntWidth::I8)),
696
-            (InstKind::ICmp(CmpOp::Lt, ValueId(0), ValueId(1)), IrType::Bool),
780
+            (
781
+                InstKind::ConstInt(-1, IntWidth::I8),
782
+                IrType::Int(IntWidth::I8),
783
+            ),
784
+            (
785
+                InstKind::ConstInt(1, IntWidth::I8),
786
+                IrType::Int(IntWidth::I8),
787
+            ),
788
+            (
789
+                InstKind::ICmp(CmpOp::Lt, ValueId(0), ValueId(1)),
790
+                IrType::Bool,
791
+            ),
697792
         ]);
698793
         assert!(ConstFold.run(&mut m));
699
-        assert!(matches!(first_block_kinds(&m)[2], InstKind::ConstBool(true)));
794
+        assert!(matches!(
795
+            first_block_kinds(&m)[2],
796
+            InstKind::ConstBool(true)
797
+        ));
700798
     }
701799
 
702800
     #[test]
703801
     fn shl_power_of_two() {
704802
         let (mut m, _) = make_module_with(vec![
705
-            (InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32)),
706
-            (InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32)),
707
-            (InstKind::Shl(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I32)),
803
+            (
804
+                InstKind::ConstInt(1, IntWidth::I32),
805
+                IrType::Int(IntWidth::I32),
806
+            ),
807
+            (
808
+                InstKind::ConstInt(3, IntWidth::I32),
809
+                IrType::Int(IntWidth::I32),
810
+            ),
811
+            (
812
+                InstKind::Shl(ValueId(0), ValueId(1)),
813
+                IrType::Int(IntWidth::I32),
814
+            ),
708815
         ]);
709816
         assert!(ConstFold.run(&mut m));
710817
         match first_block_kinds(&m)[2] {
@@ -717,8 +824,14 @@ mod tests {
717824
     fn int_to_float_chain() {
718825
         // const(42:i32) → int_to_float → const(42.0:f64)
719826
         let (mut m, _) = make_module_with(vec![
720
-            (InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32)),
721
-            (InstKind::IntToFloat(ValueId(0), FloatWidth::F64), IrType::Float(FloatWidth::F64)),
827
+            (
828
+                InstKind::ConstInt(42, IntWidth::I32),
829
+                IrType::Int(IntWidth::I32),
830
+            ),
831
+            (
832
+                InstKind::IntToFloat(ValueId(0), FloatWidth::F64),
833
+                IrType::Float(FloatWidth::F64),
834
+            ),
722835
         ]);
723836
         assert!(ConstFold.run(&mut m));
724837
         match first_block_kinds(&m)[1] {
@@ -731,9 +844,18 @@ mod tests {
731844
     fn select_on_known_cond_picks_branch() {
732845
         let (mut m, _) = make_module_with(vec![
733846
             (InstKind::ConstBool(true), IrType::Bool),
734
-            (InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32)),
735
-            (InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32)),
736
-            (InstKind::Select(ValueId(0), ValueId(1), ValueId(2)), IrType::Int(IntWidth::I32)),
847
+            (
848
+                InstKind::ConstInt(10, IntWidth::I32),
849
+                IrType::Int(IntWidth::I32),
850
+            ),
851
+            (
852
+                InstKind::ConstInt(20, IntWidth::I32),
853
+                IrType::Int(IntWidth::I32),
854
+            ),
855
+            (
856
+                InstKind::Select(ValueId(0), ValueId(1), ValueId(2)),
857
+                IrType::Int(IntWidth::I32),
858
+            ),
737859
         ]);
738860
         assert!(ConstFold.run(&mut m));
739861
         match first_block_kinds(&m)[3] {
@@ -746,24 +868,45 @@ mod tests {
746868
     fn fixpoint_via_chained_constants() {
747869
         // (3 + 4) * 2 = 14, where the inner add must fold first.
748870
         let (mut m, _) = make_module_with(vec![
749
-            (InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32)),
750
-            (InstKind::ConstInt(4, IntWidth::I32), IrType::Int(IntWidth::I32)),
751
-            (InstKind::IAdd(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I32)),
752
-            (InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32)),
753
-            (InstKind::IMul(ValueId(2), ValueId(3)), IrType::Int(IntWidth::I32)),
871
+            (
872
+                InstKind::ConstInt(3, IntWidth::I32),
873
+                IrType::Int(IntWidth::I32),
874
+            ),
875
+            (
876
+                InstKind::ConstInt(4, IntWidth::I32),
877
+                IrType::Int(IntWidth::I32),
878
+            ),
879
+            (
880
+                InstKind::IAdd(ValueId(0), ValueId(1)),
881
+                IrType::Int(IntWidth::I32),
882
+            ),
883
+            (
884
+                InstKind::ConstInt(2, IntWidth::I32),
885
+                IrType::Int(IntWidth::I32),
886
+            ),
887
+            (
888
+                InstKind::IMul(ValueId(2), ValueId(3)),
889
+                IrType::Int(IntWidth::I32),
890
+            ),
754891
         ]);
755892
         // A single pass already handles this because we walk in order.
756893
         assert!(ConstFold.run(&mut m));
757894
         let kinds = first_block_kinds(&m);
758
-        assert!(matches!(kinds[2], InstKind::ConstInt(7,  IntWidth::I32)));
895
+        assert!(matches!(kinds[2], InstKind::ConstInt(7, IntWidth::I32)));
759896
         assert!(matches!(kinds[4], InstKind::ConstInt(14, IntWidth::I32)));
760897
     }
761898
 
762899
     #[test]
763900
     fn nan_float_to_int_left_alone() {
764901
         let (mut m, _) = make_module_with(vec![
765
-            (InstKind::ConstFloat(f64::NAN, FloatWidth::F64), IrType::Float(FloatWidth::F64)),
766
-            (InstKind::FloatToInt(ValueId(0), IntWidth::I32), IrType::Int(IntWidth::I32)),
902
+            (
903
+                InstKind::ConstFloat(f64::NAN, FloatWidth::F64),
904
+                IrType::Float(FloatWidth::F64),
905
+            ),
906
+            (
907
+                InstKind::FloatToInt(ValueId(0), IntWidth::I32),
908
+                IrType::Int(IntWidth::I32),
909
+            ),
767910
         ]);
768911
         assert!(!ConstFold.run(&mut m));
769912
         assert!(matches!(first_block_kinds(&m)[1], InstKind::FloatToInt(..)));
src/opt/const_prop.rsmodified
106 lines changed — click to load
@@ -88,7 +88,9 @@ fn collect_consts(func: &Function) -> HashMap<ValueId, Const> {
8888
 pub struct ConstProp;
8989
 
9090
 impl Pass for ConstProp {
91
-    fn name(&self) -> &'static str { "const-prop" }
91
+    fn name(&self) -> &'static str {
92
+        "const-prop"
93
+    }
9294
 
9395
     fn run(&self, module: &mut Module) -> bool {
9496
         let mut changed = false;
@@ -96,7 +98,9 @@ impl Pass for ConstProp {
9698
             let consts = collect_consts(func);
9799
             let mut local_changed = false;
98100
             for block in &mut func.blocks {
99
-                let Some(term) = block.terminator.take() else { continue };
101
+                let Some(term) = block.terminator.take() else {
102
+                    continue;
103
+                };
100104
                 let new_term = simplify_terminator(term, &consts, &mut local_changed);
101105
                 block.terminator = Some(new_term);
102106
             }
@@ -118,7 +122,13 @@ fn simplify_terminator(
118122
     changed: &mut bool,
119123
 ) -> Terminator {
120124
     match term {
121
-        Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args } => {
125
+        Terminator::CondBranch {
126
+            cond,
127
+            true_dest,
128
+            true_args,
129
+            false_dest,
130
+            false_args,
131
+        } => {
122132
             if let Some(Const::Bool(c)) = consts.get(&cond).copied() {
123133
                 *changed = true;
124134
                 if c {
@@ -127,10 +137,20 @@ fn simplify_terminator(
127137
                     Terminator::Branch(false_dest, false_args)
128138
                 }
129139
             } else {
130
-                Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args }
140
+                Terminator::CondBranch {
141
+                    cond,
142
+                    true_dest,
143
+                    true_args,
144
+                    false_dest,
145
+                    false_args,
146
+                }
131147
             }
132148
         }
133
-        Terminator::Switch { selector, cases, default } => {
149
+        Terminator::Switch {
150
+            selector,
151
+            cases,
152
+            default,
153
+        } => {
134154
             if let Some(Const::Int(sv, w)) = consts.get(&selector).copied() {
135155
                 // `sv` is already canonical (sign-extended at width)
136156
                 // thanks to the M4-4 normalization in `Const::from_inst`.
@@ -138,14 +158,20 @@ fn simplify_terminator(
138158
                 // canonical, so we still normalize them before
139159
                 // comparing.
140160
                 *changed = true;
141
-                let target = cases.iter().find(|(k, _)| sext(*k, w.bits()) == sv)
161
+                let target = cases
162
+                    .iter()
163
+                    .find(|(k, _)| sext(*k, w.bits()) == sv)
142164
                     .map(|(_, b)| *b)
143165
                     .unwrap_or(default);
144166
                 // Switch targets in our IR cannot have block params, so
145167
                 // an empty arg vec is correct.
146168
                 Terminator::Branch(target, vec![])
147169
             } else {
148
-                Terminator::Switch { selector, cases, default }
170
+                Terminator::Switch {
171
+                    selector,
172
+                    cases,
173
+                    default,
174
+                }
149175
             }
150176
         }
151177
         other => other,
@@ -153,8 +179,9 @@ fn simplify_terminator(
153179
 }
154180
 
155181
 fn sext(v: i64, bits: u32) -> i64 {
156
-    if bits >= 64 { v }
157
-    else {
182
+    if bits >= 64 {
183
+        v
184
+    } else {
158185
         let shift = 64 - bits;
159186
         (v << shift) >> shift
160187
     }
@@ -164,11 +191,15 @@ fn sext(v: i64, bits: u32) -> i64 {
164191
 mod tests {
165192
     use super::*;
166193
     use crate::ir::types::IrType;
167
-    use crate::lexer::{Span, Position};
194
+    use crate::lexer::{Position, Span};
168195
 
169196
     fn dummy_span() -> Span {
170197
         let p = Position { line: 1, col: 1 };
171
-        Span { start: p, end: p, file_id: 0 }
198
+        Span {
199
+            start: p,
200
+            end: p,
201
+            file_id: 0,
202
+        }
172203
     }
173204
 
174205
     #[test]
src/opt/cse.rsmodified
287 lines changed — click to load
@@ -63,13 +63,29 @@ struct Key {
6363
 /// instruction is impure or otherwise not a CSE candidate.
6464
 fn key_of(inst: &Inst) -> Option<Key> {
6565
     let mk = |tag: u32, ops: Vec<ValueId>, aux: i128| -> Option<Key> {
66
-        Some(Key { tag, operands: ops, aux, name: None, ty: inst.ty.clone() })
66
+        Some(Key {
67
+            tag,
68
+            operands: ops,
69
+            aux,
70
+            name: None,
71
+            ty: inst.ty.clone(),
72
+        })
6773
     };
6874
     let mk_named = |tag: u32, name: String| -> Option<Key> {
69
-        Some(Key { tag, operands: vec![], aux: 0, name: Some(name), ty: inst.ty.clone() })
75
+        Some(Key {
76
+            tag,
77
+            operands: vec![],
78
+            aux: 0,
79
+            name: Some(name),
80
+            ty: inst.ty.clone(),
81
+        })
7082
     };
7183
     let canon = |a: ValueId, b: ValueId| -> Vec<ValueId> {
72
-        if a.0 <= b.0 { vec![a, b] } else { vec![b, a] }
84
+        if a.0 <= b.0 {
85
+            vec![a, b]
86
+        } else {
87
+            vec![b, a]
88
+        }
7389
     };
7490
 
7591
     match &inst.kind {
@@ -87,7 +103,7 @@ fn key_of(inst: &Inst) -> Option<Key> {
87103
         // at different bit patterns dedupe. Example: `ConstInt(255, I8)`
88104
         // and `ConstInt(-1, I8)` both represent -1 in i8 — keying on
89105
         // the raw `*v` fails to dedupe them.
90
-        InstKind::ConstInt(v, w)   => {
106
+        InstKind::ConstInt(v, w) => {
91107
             let bits = w.bits();
92108
             // Sign-extend at width: low `bits` bits → i64 sign-extended.
93109
             let signed = if bits >= 128 {
@@ -99,7 +115,7 @@ fn key_of(inst: &Inst) -> Option<Key> {
99115
             mk(1, vec![], signed)
100116
         }
101117
         InstKind::ConstFloat(v, _) => mk(2, vec![], v.to_bits() as i128),
102
-        InstKind::ConstBool(b)     => mk(3, vec![], if *b { 1 } else { 0 }),
118
+        InstKind::ConstBool(b) => mk(3, vec![], if *b { 1 } else { 0 }),
103119
 
104120
         // Integer arithmetic --------------------------------------------
105121
         InstKind::IAdd(a, b) => mk(10, canon(*a, *b), 0),
@@ -107,58 +123,66 @@ fn key_of(inst: &Inst) -> Option<Key> {
107123
         InstKind::IMul(a, b) => mk(12, canon(*a, *b), 0),
108124
         InstKind::IDiv(a, b) => mk(13, vec![*a, *b], 0),
109125
         InstKind::IMod(a, b) => mk(14, vec![*a, *b], 0),
110
-        InstKind::INeg(a)    => mk(15, vec![*a], 0),
126
+        InstKind::INeg(a) => mk(15, vec![*a], 0),
111127
 
112128
         // Float arithmetic ----------------------------------------------
113129
         InstKind::FAdd(a, b) => mk(20, canon(*a, *b), 0),
114130
         InstKind::FSub(a, b) => mk(21, vec![*a, *b], 0),
115131
         InstKind::FMul(a, b) => mk(22, canon(*a, *b), 0),
116132
         InstKind::FDiv(a, b) => mk(23, vec![*a, *b], 0),
117
-        InstKind::FNeg(a)    => mk(24, vec![*a], 0),
118
-        InstKind::FAbs(a)    => mk(25, vec![*a], 0),
119
-        InstKind::FSqrt(a)   => mk(26, vec![*a], 0),
133
+        InstKind::FNeg(a) => mk(24, vec![*a], 0),
134
+        InstKind::FAbs(a) => mk(25, vec![*a], 0),
135
+        InstKind::FSqrt(a) => mk(26, vec![*a], 0),
120136
         InstKind::FPow(a, b) => mk(27, vec![*a, *b], 0),
121137
 
122138
         // Comparisons ---------------------------------------------------
123139
         InstKind::ICmp(op, a, b) => {
124140
             let aux = *op as i128;
125
-            let ops = match op { CmpOp::Eq | CmpOp::Ne => canon(*a, *b), _ => vec![*a, *b] };
141
+            let ops = match op {
142
+                CmpOp::Eq | CmpOp::Ne => canon(*a, *b),
143
+                _ => vec![*a, *b],
144
+            };
126145
             mk(30, ops, aux)
127146
         }
128147
         InstKind::FCmp(op, a, b) => {
129148
             let aux = *op as i128;
130
-            let ops = match op { CmpOp::Eq | CmpOp::Ne => canon(*a, *b), _ => vec![*a, *b] };
149
+            let ops = match op {
150
+                CmpOp::Eq | CmpOp::Ne => canon(*a, *b),
151
+                _ => vec![*a, *b],
152
+            };
131153
             mk(31, ops, aux)
132154
         }
133155
 
134156
         // Logic ---------------------------------------------------------
135157
         InstKind::And(a, b) => mk(40, canon(*a, *b), 0),
136
-        InstKind::Or(a, b)  => mk(41, canon(*a, *b), 0),
137
-        InstKind::Not(a)    => mk(42, vec![*a], 0),
158
+        InstKind::Or(a, b) => mk(41, canon(*a, *b), 0),
159
+        InstKind::Not(a) => mk(42, vec![*a], 0),
138160
 
139161
         InstKind::Select(c, t, f) => mk(43, vec![*c, *t, *f], 0),
140162
 
141163
         // Bitwise -------------------------------------------------------
142164
         InstKind::BitAnd(a, b) => mk(50, canon(*a, *b), 0),
143
-        InstKind::BitOr(a, b)  => mk(51, canon(*a, *b), 0),
165
+        InstKind::BitOr(a, b) => mk(51, canon(*a, *b), 0),
144166
         InstKind::BitXor(a, b) => mk(52, canon(*a, *b), 0),
145
-        InstKind::BitNot(a)    => mk(53, vec![*a], 0),
146
-        InstKind::Shl(a, b)    => mk(54, vec![*a, *b], 0),
147
-        InstKind::LShr(a, b)   => mk(55, vec![*a, *b], 0),
148
-        InstKind::AShr(a, b)   => mk(56, vec![*a, *b], 0),
149
-        InstKind::CountLeadingZeros(a)  => mk(57, vec![*a], 0),
167
+        InstKind::BitNot(a) => mk(53, vec![*a], 0),
168
+        InstKind::Shl(a, b) => mk(54, vec![*a, *b], 0),
169
+        InstKind::LShr(a, b) => mk(55, vec![*a, *b], 0),
170
+        InstKind::AShr(a, b) => mk(56, vec![*a, *b], 0),
171
+        InstKind::CountLeadingZeros(a) => mk(57, vec![*a], 0),
150172
         InstKind::CountTrailingZeros(a) => mk(58, vec![*a], 0),
151
-        InstKind::PopCount(a)           => mk(59, vec![*a], 0),
173
+        InstKind::PopCount(a) => mk(59, vec![*a], 0),
152174
 
153175
         // Conversions ---------------------------------------------------
154
-        InstKind::IntToFloat(v, fw)     => mk(60, vec![*v], fw.bits() as i128),
155
-        InstKind::FloatToInt(v, w)      => mk(61, vec![*v], w.bits() as i128),
156
-        InstKind::FloatExtend(v, fw)    => mk(62, vec![*v], fw.bits() as i128),
157
-        InstKind::FloatTrunc(v, fw)     => mk(63, vec![*v], fw.bits() as i128),
158
-        InstKind::IntExtend(v, w, sgn)  => mk(64, vec![*v], (w.bits() as i128) | ((*sgn as i128) << 32)),
159
-        InstKind::IntTrunc(v, w)        => mk(65, vec![*v], w.bits() as i128),
160
-        InstKind::PtrToInt(v)           => mk(66, vec![*v], 0),
161
-        InstKind::IntToPtr(v, _)        => mk(67, vec![*v], 0),
176
+        InstKind::IntToFloat(v, fw) => mk(60, vec![*v], fw.bits() as i128),
177
+        InstKind::FloatToInt(v, w) => mk(61, vec![*v], w.bits() as i128),
178
+        InstKind::FloatExtend(v, fw) => mk(62, vec![*v], fw.bits() as i128),
179
+        InstKind::FloatTrunc(v, fw) => mk(63, vec![*v], fw.bits() as i128),
180
+        InstKind::IntExtend(v, w, sgn) => {
181
+            mk(64, vec![*v], (w.bits() as i128) | ((*sgn as i128) << 32))
182
+        }
183
+        InstKind::IntTrunc(v, w) => mk(65, vec![*v], w.bits() as i128),
184
+        InstKind::PtrToInt(v) => mk(66, vec![*v], 0),
185
+        InstKind::IntToPtr(v, _) => mk(67, vec![*v], 0),
162186
 
163187
         // Address arithmetic --------------------------------------------
164188
         InstKind::GetElementPtr(base, idxs) => {
@@ -188,7 +212,9 @@ fn key_of(inst: &Inst) -> Option<Key> {
188212
 pub struct LocalCse;
189213
 
190214
 impl Pass for LocalCse {
191
-    fn name(&self) -> &'static str { "local-cse" }
215
+    fn name(&self) -> &'static str {
216
+        "local-cse"
217
+    }
192218
 
193219
     fn run(&self, module: &mut Module) -> bool {
194220
         let mut changed = false;
@@ -211,7 +237,9 @@ impl Pass for LocalCse {
211237
                     }
212238
                 }
213239
             }
214
-            if rewrite_map.is_empty() { continue; }
240
+            if rewrite_map.is_empty() {
241
+                continue;
242
+            }
215243
 
216244
             // Audit B-7: in **local** CSE, every entry maps a later
217245
             // duplicate to its block's *first* occurrence — and that
@@ -261,18 +289,27 @@ fn substitute_uses_batch(func: &mut Function, rewrites: &HashMap<ValueId, ValueI
261289
 #[cfg(test)]
262290
 mod tests {
263291
     use super::*;
264
-    use crate::ir::types::{IrType, IntWidth, FloatWidth};
265
-    use crate::lexer::{Span, Position};
292
+    use crate::ir::types::{FloatWidth, IntWidth, IrType};
293
+    use crate::lexer::{Position, Span};
266294
 
267295
     fn dummy_span() -> Span {
268296
         let p = Position { line: 1, col: 1 };
269
-        Span { start: p, end: p, file_id: 0 }
297
+        Span {
298
+            start: p,
299
+            end: p,
300
+            file_id: 0,
301
+        }
270302
     }
271303
 
272304
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
273305
         let id = f.next_value_id();
274306
         let entry = f.entry;
275
-        f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
307
+        f.block_mut(entry).insts.push(Inst {
308
+            id,
309
+            kind,
310
+            ty,
311
+            span: dummy_span(),
312
+        });
276313
         id
277314
     }
278315
 
@@ -285,8 +322,16 @@ mod tests {
285322
         // ret %3 → after CSE → ret %2 (and %3 is dead)
286323
         let mut m = Module::new("t".into());
287324
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
288
-        let a = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
289
-        let b = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32));
325
+        let a = push(
326
+            &mut f,
327
+            InstKind::ConstInt(1, IntWidth::I32),
328
+            IrType::Int(IntWidth::I32),
329
+        );
330
+        let b = push(
331
+            &mut f,
332
+            InstKind::ConstInt(2, IntWidth::I32),
333
+            IrType::Int(IntWidth::I32),
334
+        );
290335
         let c1 = push(&mut f, InstKind::IAdd(a, b), IrType::Int(IntWidth::I32));
291336
         let c2 = push(&mut f, InstKind::IAdd(a, b), IrType::Int(IntWidth::I32));
292337
         let entry = f.entry;
@@ -308,8 +353,16 @@ mod tests {
308353
         // Should canonicalize to the same key.
309354
         let mut m = Module::new("t".into());
310355
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
311
-        let a = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
312
-        let b = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32));
356
+        let a = push(
357
+            &mut f,
358
+            InstKind::ConstInt(1, IntWidth::I32),
359
+            IrType::Int(IntWidth::I32),
360
+        );
361
+        let b = push(
362
+            &mut f,
363
+            InstKind::ConstInt(2, IntWidth::I32),
364
+            IrType::Int(IntWidth::I32),
365
+        );
313366
         let c1 = push(&mut f, InstKind::IAdd(a, b), IrType::Int(IntWidth::I32));
314367
         let c2 = push(&mut f, InstKind::IAdd(b, a), IrType::Int(IntWidth::I32));
315368
         let _ = c2;
@@ -328,8 +381,16 @@ mod tests {
328381
     fn non_commutative_isub_does_not_dedupe_swapped() {
329382
         let mut m = Module::new("t".into());
330383
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
331
-        let a = push(&mut f, InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32));
332
-        let b = push(&mut f, InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
384
+        let a = push(
385
+            &mut f,
386
+            InstKind::ConstInt(5, IntWidth::I32),
387
+            IrType::Int(IntWidth::I32),
388
+        );
389
+        let b = push(
390
+            &mut f,
391
+            InstKind::ConstInt(3, IntWidth::I32),
392
+            IrType::Int(IntWidth::I32),
393
+        );
333394
         let _c1 = push(&mut f, InstKind::ISub(a, b), IrType::Int(IntWidth::I32));
334395
         let c2 = push(&mut f, InstKind::ISub(b, a), IrType::Int(IntWidth::I32));
335396
         let entry = f.entry;
@@ -345,7 +406,8 @@ mod tests {
345406
         // Loads must NOT be deduplicated by local CSE.
346407
         let mut m = Module::new("t".into());
347408
         let mut f = Function::new("f".into(), vec![], IrType::Void);
348
-        let addr = push(&mut f,
409
+        let addr = push(
410
+            &mut f,
349411
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
350412
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
351413
         );
@@ -362,8 +424,16 @@ mod tests {
362424
     fn fmul_dedupes() {
363425
         let mut m = Module::new("t".into());
364426
         let mut f = Function::new("f".into(), vec![], IrType::Float(FloatWidth::F64));
365
-        let a = push(&mut f, InstKind::ConstFloat(1.5, FloatWidth::F64), IrType::Float(FloatWidth::F64));
366
-        let b = push(&mut f, InstKind::ConstFloat(2.5, FloatWidth::F64), IrType::Float(FloatWidth::F64));
427
+        let a = push(
428
+            &mut f,
429
+            InstKind::ConstFloat(1.5, FloatWidth::F64),
430
+            IrType::Float(FloatWidth::F64),
431
+        );
432
+        let b = push(
433
+            &mut f,
434
+            InstKind::ConstFloat(2.5, FloatWidth::F64),
435
+            IrType::Float(FloatWidth::F64),
436
+        );
367437
         let m1 = push(&mut f, InstKind::FMul(a, b), IrType::Float(FloatWidth::F64));
368438
         let m2 = push(&mut f, InstKind::FMul(b, a), IrType::Float(FloatWidth::F64));
369439
         let entry = f.entry;
@@ -382,8 +452,16 @@ mod tests {
382452
         // Lt is not commutative — must not collapse.
383453
         let mut m = Module::new("t".into());
384454
         let mut f = Function::new("f".into(), vec![], IrType::Bool);
385
-        let a = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
386
-        let b = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32));
455
+        let a = push(
456
+            &mut f,
457
+            InstKind::ConstInt(1, IntWidth::I32),
458
+            IrType::Int(IntWidth::I32),
459
+        );
460
+        let b = push(
461
+            &mut f,
462
+            InstKind::ConstInt(2, IntWidth::I32),
463
+            IrType::Int(IntWidth::I32),
464
+        );
387465
         let _c1 = push(&mut f, InstKind::ICmp(CmpOp::Lt, a, b), IrType::Bool);
388466
         let c2 = push(&mut f, InstKind::ICmp(CmpOp::Lt, b, a), IrType::Bool);
389467
         let entry = f.entry;
src/opt/dce.rsmodified
298 lines changed — click to load
@@ -36,7 +36,7 @@
3636
 //! refine this.
3737
 
3838
 use super::pass::Pass;
39
-use super::util::{inst_uses, terminator_uses, prune_unreachable};
39
+use super::util::{inst_uses, prune_unreachable, terminator_uses};
4040
 use crate::ir::inst::*;
4141
 use std::collections::{HashMap, HashSet};
4242
 
@@ -52,9 +52,10 @@ fn has_side_effect(kind: &InstKind, pure_internal_calls: &[bool]) -> bool {
5252
             // future store/call). Treat as side-effecting for safety.
5353
             | InstKind::Alloca(..)
5454
     ) || match kind {
55
-        InstKind::Call(FuncRef::Internal(idx), _) => {
56
-            !pure_internal_calls.get(*idx as usize).copied().unwrap_or(false)
57
-        }
55
+        InstKind::Call(FuncRef::Internal(idx), _) => !pure_internal_calls
56
+            .get(*idx as usize)
57
+            .copied()
58
+            .unwrap_or(false),
5859
         InstKind::Call(..) => true,
5960
         _ => false,
6061
     }
@@ -109,8 +110,12 @@ fn dce_function(func: &mut Function, pure_internal_calls: &[bool]) -> bool {
109110
             for block in &mut func.blocks {
110111
                 let before = block.insts.len();
111112
                 block.insts.retain(|inst| {
112
-                    if has_side_effect(&inst.kind, pure_internal_calls) { return true; }
113
-                    if live.contains(&inst.id) { return true; }
113
+                    if has_side_effect(&inst.kind, pure_internal_calls) {
114
+                        return true;
115
+                    }
116
+                    if live.contains(&inst.id) {
117
+                        return true;
118
+                    }
114119
                     false
115120
                 });
116121
                 if block.insts.len() != before {
@@ -126,7 +131,9 @@ fn dce_function(func: &mut Function, pure_internal_calls: &[bool]) -> bool {
126131
             outer_changed = true;
127132
         }
128133
     }
129
-    if prune_unreachable(func) { any_change = true; }
134
+    if prune_unreachable(func) {
135
+        any_change = true;
136
+    }
130137
     any_change
131138
 }
132139
 
@@ -146,19 +153,25 @@ fn remove_dead_block_params(func: &mut Function) -> bool {
146153
 
147154
     let mut by_block: HashMap<BlockId, Vec<usize>> = HashMap::new();
148155
     for block in func.blocks.iter() {
149
-        if block.id == func.entry { continue; }
156
+        if block.id == func.entry {
157
+            continue;
158
+        }
150159
         for (idx, p) in block.params.iter().enumerate() {
151160
             if !live.contains(&p.id) {
152161
                 by_block.entry(block.id).or_default().push(idx);
153162
             }
154163
         }
155164
     }
156
-    if by_block.is_empty() { return false; }
165
+    if by_block.is_empty() {
166
+        return false;
167
+    }
157168
 
158169
     // Map BlockId → vec index. LICM/DCE never structurally reorder
159170
     // `func.blocks`; only the inst vectors change. So this stays
160171
     // valid for the lifetime of this call.
161
-    let block_index: HashMap<BlockId, usize> = func.blocks.iter()
172
+    let block_index: HashMap<BlockId, usize> = func
173
+        .blocks
174
+        .iter()
162175
         .enumerate()
163176
         .map(|(i, b)| (b.id, i))
164177
         .collect();
@@ -199,20 +212,38 @@ fn remove_dead_block_params(func: &mut Function) -> bool {
199212
 fn drop_branch_arg(term: &mut Terminator, target: BlockId, idx: usize) {
200213
     match term {
201214
         Terminator::Branch(d, args) if *d == target => {
202
-            debug_assert!(idx < args.len(),
203
-                "drop_branch_arg: branch arg list out of sync with target params");
204
-            if idx < args.len() { args.remove(idx); }
215
+            debug_assert!(
216
+                idx < args.len(),
217
+                "drop_branch_arg: branch arg list out of sync with target params"
218
+            );
219
+            if idx < args.len() {
220
+                args.remove(idx);
221
+            }
205222
         }
206
-        Terminator::CondBranch { true_dest, true_args, false_dest, false_args, .. } => {
223
+        Terminator::CondBranch {
224
+            true_dest,
225
+            true_args,
226
+            false_dest,
227
+            false_args,
228
+            ..
229
+        } => {
207230
             if *true_dest == target {
208
-                debug_assert!(idx < true_args.len(),
209
-                    "drop_branch_arg: cond_branch true_args out of sync");
210
-                if idx < true_args.len() { true_args.remove(idx); }
231
+                debug_assert!(
232
+                    idx < true_args.len(),
233
+                    "drop_branch_arg: cond_branch true_args out of sync"
234
+                );
235
+                if idx < true_args.len() {
236
+                    true_args.remove(idx);
237
+                }
211238
             }
212239
             if *false_dest == target {
213
-                debug_assert!(idx < false_args.len(),
214
-                    "drop_branch_arg: cond_branch false_args out of sync");
215
-                if idx < false_args.len() { false_args.remove(idx); }
240
+                debug_assert!(
241
+                    idx < false_args.len(),
242
+                    "drop_branch_arg: cond_branch false_args out of sync"
243
+                );
244
+                if idx < false_args.len() {
245
+                    false_args.remove(idx);
246
+                }
216247
             }
217248
         }
218249
         Terminator::Switch { cases, default, .. } => {
@@ -221,11 +252,12 @@ fn drop_branch_arg(term: &mut Terminator, target: BlockId, idx: usize) {
221252
             // M-6: if we ever see a Switch that branches into a
222253
             // block we're stripping params from, that's a real IR
223254
             // validity bug. Assert instead of silently skipping.
224
-            let touches_target = cases.iter().any(|(_, b)| *b == target)
225
-                || *default == target;
226
-            debug_assert!(!touches_target,
255
+            let touches_target = cases.iter().any(|(_, b)| *b == target) || *default == target;
256
+            debug_assert!(
257
+                !touches_target,
227258
                 "drop_branch_arg: Switch terminator branches to a block with params \
228
-                 — verifier should reject this construction");
259
+                 — verifier should reject this construction"
260
+            );
229261
         }
230262
         _ => {}
231263
     }
@@ -234,12 +266,17 @@ fn drop_branch_arg(term: &mut Terminator, target: BlockId, idx: usize) {
234266
 pub struct Dce;
235267
 
236268
 impl Pass for Dce {
237
-    fn name(&self) -> &'static str { "dce" }
269
+    fn name(&self) -> &'static str {
270
+        "dce"
271
+    }
238272
     fn run(&self, module: &mut Module) -> bool {
239
-        let pure_internal_calls: Vec<bool> = module.functions.iter().map(|func| func.is_pure).collect();
273
+        let pure_internal_calls: Vec<bool> =
274
+            module.functions.iter().map(|func| func.is_pure).collect();
240275
         let mut changed = false;
241276
         for func in &mut module.functions {
242
-            if dce_function(func, &pure_internal_calls) { changed = true; }
277
+            if dce_function(func, &pure_internal_calls) {
278
+                changed = true;
279
+            }
243280
         }
244281
         changed
245282
     }
@@ -248,18 +285,27 @@ impl Pass for Dce {
248285
 #[cfg(test)]
249286
 mod tests {
250287
     use super::*;
251
-    use crate::ir::types::{IrType, IntWidth, FloatWidth};
252
-    use crate::lexer::{Span, Position};
288
+    use crate::ir::types::{FloatWidth, IntWidth, IrType};
289
+    use crate::lexer::{Position, Span};
253290
 
254291
     fn dummy_span() -> Span {
255292
         let p = Position { line: 1, col: 1 };
256
-        Span { start: p, end: p, file_id: 0 }
293
+        Span {
294
+            start: p,
295
+            end: p,
296
+            file_id: 0,
297
+        }
257298
     }
258299
 
259300
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
260301
         let id = f.next_value_id();
261302
         let entry = f.entry;
262
-        f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
303
+        f.block_mut(entry).insts.push(Inst {
304
+            id,
305
+            kind,
306
+            ty,
307
+            span: dummy_span(),
308
+        });
263309
         id
264310
     }
265311
 
@@ -267,7 +313,11 @@ mod tests {
267313
     fn removes_unused_const() {
268314
         let mut m = Module::new("t".into());
269315
         let mut f = Function::new("f".into(), vec![], IrType::Void);
270
-        push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
316
+        push(
317
+            &mut f,
318
+            InstKind::ConstInt(7, IntWidth::I32),
319
+            IrType::Int(IntWidth::I32),
320
+        );
271321
         let entry = f.entry;
272322
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
273323
         m.add_function(f);
@@ -280,7 +330,11 @@ mod tests {
280330
     fn keeps_const_used_by_return() {
281331
         let mut m = Module::new("t".into());
282332
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
283
-        let v = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
333
+        let v = push(
334
+            &mut f,
335
+            InstKind::ConstInt(7, IntWidth::I32),
336
+            IrType::Int(IntWidth::I32),
337
+        );
284338
         let entry = f.entry;
285339
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(v)));
286340
         m.add_function(f);
@@ -294,11 +348,16 @@ mod tests {
294348
         // Alloca + Store should both stay even though no one loads.
295349
         let mut m = Module::new("t".into());
296350
         let mut f = Function::new("f".into(), vec![], IrType::Void);
297
-        let addr = push(&mut f,
351
+        let addr = push(
352
+            &mut f,
298353
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
299354
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
300355
         );
301
-        let v = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
356
+        let v = push(
357
+            &mut f,
358
+            InstKind::ConstInt(1, IntWidth::I32),
359
+            IrType::Int(IntWidth::I32),
360
+        );
302361
         push(&mut f, InstKind::Store(v, addr), IrType::Void);
303362
         let entry = f.entry;
304363
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
@@ -317,8 +376,16 @@ mod tests {
317376
         // After DCE: only the terminator remains.
318377
         let mut m = Module::new("t".into());
319378
         let mut f = Function::new("f".into(), vec![], IrType::Void);
320
-        let a = push(&mut f, InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
321
-        let b = push(&mut f, InstKind::ConstInt(4, IntWidth::I32), IrType::Int(IntWidth::I32));
379
+        let a = push(
380
+            &mut f,
381
+            InstKind::ConstInt(3, IntWidth::I32),
382
+            IrType::Int(IntWidth::I32),
383
+        );
384
+        let b = push(
385
+            &mut f,
386
+            InstKind::ConstInt(4, IntWidth::I32),
387
+            IrType::Int(IntWidth::I32),
388
+        );
322389
         let c = push(&mut f, InstKind::IAdd(a, b), IrType::Int(IntWidth::I32));
323390
         let _d = push(&mut f, InstKind::INeg(c), IrType::Int(IntWidth::I32));
324391
         let entry = f.entry;
@@ -333,7 +400,8 @@ mod tests {
333400
     fn keeps_call_even_if_result_unused() {
334401
         let mut m = Module::new("t".into());
335402
         let mut f = Function::new("f".into(), vec![], IrType::Void);
336
-        push(&mut f,
403
+        push(
404
+            &mut f,
337405
             InstKind::RuntimeCall(RuntimeFunc::PrintNewline, vec![]),
338406
             IrType::Void,
339407
         );
@@ -351,7 +419,11 @@ mod tests {
351419
 
352420
         let mut callee = Function::new("pure_fn".into(), vec![], IrType::Int(IntWidth::I32));
353421
         callee.is_pure = true;
354
-        let c = push(&mut callee, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
422
+        let c = push(
423
+            &mut callee,
424
+            InstKind::ConstInt(7, IntWidth::I32),
425
+            IrType::Int(IntWidth::I32),
426
+        );
355427
         let callee_entry = callee.entry;
356428
         callee.block_mut(callee_entry).terminator = Some(Terminator::Return(Some(c)));
357429
         m.add_function(callee);
@@ -367,15 +439,26 @@ mod tests {
367439
         m.add_function(caller);
368440
 
369441
         assert!(Dce.run(&mut m));
370
-        assert!(m.functions[1].blocks[0].insts.is_empty(), "unused PURE call should be removed");
442
+        assert!(
443
+            m.functions[1].blocks[0].insts.is_empty(),
444
+            "unused PURE call should be removed"
445
+        );
371446
     }
372447
 
373448
     #[test]
374449
     fn float_chain_is_dead() {
375450
         let mut m = Module::new("t".into());
376451
         let mut f = Function::new("f".into(), vec![], IrType::Void);
377
-        let a = push(&mut f, InstKind::ConstFloat(1.5, FloatWidth::F64), IrType::Float(FloatWidth::F64));
378
-        let b = push(&mut f, InstKind::ConstFloat(2.5, FloatWidth::F64), IrType::Float(FloatWidth::F64));
452
+        let a = push(
453
+            &mut f,
454
+            InstKind::ConstFloat(1.5, FloatWidth::F64),
455
+            IrType::Float(FloatWidth::F64),
456
+        );
457
+        let b = push(
458
+            &mut f,
459
+            InstKind::ConstFloat(2.5, FloatWidth::F64),
460
+            IrType::Float(FloatWidth::F64),
461
+        );
379462
         let _ = push(&mut f, InstKind::FAdd(a, b), IrType::Float(FloatWidth::F64));
380463
         let entry = f.entry;
381464
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
src/opt/dead_arg.rsmodified
73 lines changed — click to load
@@ -10,7 +10,9 @@ use super::pass::Pass;
1010
 pub struct DeadArgElim;
1111
 
1212
 impl Pass for DeadArgElim {
13
-    fn name(&self) -> &'static str { "dead-arg-elim" }
13
+    fn name(&self) -> &'static str {
14
+        "dead-arg-elim"
15
+    }
1416
 
1517
     fn run(&self, module: &mut Module) -> bool {
1618
         let mut live_masks: Vec<Vec<bool>> = module
@@ -196,9 +198,12 @@ fn block_terminator_uses_param(term: &Option<Terminator>, param_id: ValueId) ->
196198
     match term {
197199
         Some(Terminator::Return(Some(v))) => *v == param_id,
198200
         Some(Terminator::Branch(_, args)) => args.contains(&param_id),
199
-        Some(Terminator::CondBranch { cond, true_args, false_args, .. }) => {
200
-            *cond == param_id || true_args.contains(&param_id) || false_args.contains(&param_id)
201
-        }
201
+        Some(Terminator::CondBranch {
202
+            cond,
203
+            true_args,
204
+            false_args,
205
+            ..
206
+        }) => *cond == param_id || true_args.contains(&param_id) || false_args.contains(&param_id),
202207
         Some(Terminator::Switch { selector, .. }) => *selector == param_id,
203208
         _ => false,
204209
     }
@@ -207,18 +212,27 @@ fn block_terminator_uses_param(term: &Option<Terminator>, param_id: ValueId) ->
207212
 #[cfg(test)]
208213
 mod tests {
209214
     use super::*;
210
-    use crate::ir::types::{IrType, IntWidth};
215
+    use crate::ir::types::{IntWidth, IrType};
211216
     use crate::lexer::{Position, Span};
212217
 
213218
     fn span() -> Span {
214219
         let pos = Position { line: 0, col: 0 };
215
-        Span { file_id: 0, start: pos, end: pos }
220
+        Span {
221
+            file_id: 0,
222
+            start: pos,
223
+            end: pos,
224
+        }
216225
     }
217226
 
218227
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
219228
         let id = f.next_value_id();
220229
         let entry = f.entry;
221
-        f.block_mut(entry).insts.push(Inst { id, kind, ty: ty.clone(), span: span() });
230
+        f.block_mut(entry).insts.push(Inst {
231
+            id,
232
+            kind,
233
+            ty: ty.clone(),
234
+            span: span(),
235
+        });
222236
         f.register_type(id, ty);
223237
         id
224238
     }
@@ -248,8 +262,16 @@ mod tests {
248262
         module.add_function(callee);
249263
 
250264
         let mut caller = Function::new("main".into(), vec![], IrType::Int(IntWidth::I32));
251
-        let a = push(&mut caller, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
252
-        let b = push(&mut caller, InstKind::ConstInt(9, IntWidth::I32), IrType::Int(IntWidth::I32));
265
+        let a = push(
266
+            &mut caller,
267
+            InstKind::ConstInt(7, IntWidth::I32),
268
+            IrType::Int(IntWidth::I32),
269
+        );
270
+        let b = push(
271
+            &mut caller,
272
+            InstKind::ConstInt(9, IntWidth::I32),
273
+            IrType::Int(IntWidth::I32),
274
+        );
253275
         let call = push(
254276
             &mut caller,
255277
             InstKind::Call(FuncRef::Internal(0), vec![a, b]),
src/opt/dead_func.rsmodified
77 lines changed — click to load
@@ -10,18 +10,22 @@
1010
 //! (runtime, external linkage) are also kept since the call might come
1111
 //! from outside.
1212
 
13
-use std::collections::HashSet;
14
-use crate::ir::inst::*;
1513
 use super::pass::Pass;
14
+use crate::ir::inst::*;
15
+use std::collections::HashSet;
1616
 
1717
 pub struct DeadFuncElim;
1818
 
1919
 impl Pass for DeadFuncElim {
20
-    fn name(&self) -> &'static str { "dead-func-elim" }
20
+    fn name(&self) -> &'static str {
21
+        "dead-func-elim"
22
+    }
2123
 
2224
     fn run(&self, module: &mut Module) -> bool {
2325
         let n = module.functions.len();
24
-        if n <= 1 { return false; }
26
+        if n <= 1 {
27
+            return false;
28
+        }
2529
 
2630
         // Collect all function indices that are referenced by Internal calls.
2731
         let mut referenced: HashSet<u32> = HashSet::new();
@@ -78,7 +82,9 @@ impl Pass for DeadFuncElim {
7882
             .filter(|i| !referenced.contains(&(*i as u32)))
7983
             .collect();
8084
 
81
-        if dead.is_empty() { return false; }
85
+        if dead.is_empty() {
86
+            return false;
87
+        }
8288
 
8389
         // Remove in reverse order so indices stay valid.
8490
         for &idx in dead.iter().rev() {
@@ -117,13 +123,17 @@ impl Pass for DeadFuncElim {
117123
 #[cfg(test)]
118124
 mod tests {
119125
     use super::*;
120
-    use crate::ir::types::{IrType, IntWidth};
126
+    use crate::ir::types::{IntWidth, IrType};
127
+    use crate::lexer::{Position, Span};
121128
     use crate::opt::pass::Pass;
122
-    use crate::lexer::{Span, Position};
123129
 
124130
     fn span() -> Span {
125131
         let pos = Position { line: 0, col: 0 };
126
-        Span { file_id: 0, start: pos, end: pos }
132
+        Span {
133
+            file_id: 0,
134
+            start: pos,
135
+            end: pos,
136
+        }
127137
     }
128138
 
129139
     #[test]
@@ -155,7 +165,9 @@ mod tests {
155165
         let cid = caller.next_value_id();
156166
         caller.register_type(cid, IrType::Void);
157167
         caller.block_mut(caller.entry).insts.push(Inst {
158
-            id: cid, ty: IrType::Void, span: span(),
168
+            id: cid,
169
+            ty: IrType::Void,
170
+            span: span(),
159171
             kind: InstKind::Call(FuncRef::Internal(1), vec![]),
160172
         });
161173
         caller.block_mut(caller.entry).terminator = Some(Terminator::Return(None));
@@ -212,7 +224,10 @@ mod tests {
212224
 
213225
         let pass = DeadFuncElim;
214226
         let changed = pass.run(&mut m);
215
-        assert!(changed, "dead helper should be removed while keeping program body");
227
+        assert!(
228
+            changed,
229
+            "dead helper should be removed while keeping program body"
230
+        );
216231
         assert_eq!(m.functions.len(), 1);
217232
         assert_eq!(m.functions[0].name, "__prog_entry");
218233
     }
src/opt/dep_analysis.rsmodified
318 lines changed — click to load
@@ -11,8 +11,8 @@
1111
 //! - Column-major strides are compile-time constants for fixed-shape arrays.
1212
 //! - INTENT(IN) arguments cannot alias INTENT(OUT) arguments.
1313
 
14
-use std::collections::HashSet;
1514
 use crate::ir::inst::*;
15
+use std::collections::HashSet;
1616
 
1717
 // ---------------------------------------------------------------------------
1818
 // Data structures
@@ -23,16 +23,29 @@ use crate::ir::inst::*;
2323
 #[derive(Debug, Clone)]
2424
 pub struct AffineExpr {
2525
     pub constant: i64,
26
-    pub terms: Vec<(i64, ValueId)>,  // (coefficient, iv)
26
+    pub terms: Vec<(i64, ValueId)>, // (coefficient, iv)
2727
 }
2828
 
2929
 impl AffineExpr {
30
-    fn zero() -> Self { Self { constant: 0, terms: Vec::new() } }
30
+    fn zero() -> Self {
31
+        Self {
32
+            constant: 0,
33
+            terms: Vec::new(),
34
+        }
35
+    }
3136
 
32
-    fn from_const(c: i64) -> Self { Self { constant: c, terms: Vec::new() } }
37
+    fn from_const(c: i64) -> Self {
38
+        Self {
39
+            constant: c,
40
+            terms: Vec::new(),
41
+        }
42
+    }
3343
 
3444
     fn from_iv(iv: ValueId) -> Self {
35
-        Self { constant: 0, terms: vec![(1, iv)] }
45
+        Self {
46
+            constant: 0,
47
+            terms: vec![(1, iv)],
48
+        }
3649
     }
3750
 
3851
     fn add(&self, other: &Self) -> Self {
@@ -89,11 +102,7 @@ pub struct DepResult {
89102
 /// Extract an affine expression from a GEP index by walking backwards
90103
 /// through arithmetic instructions. `ivs` is the set of known induction
91104
 /// variables for the enclosing loop nest.
92
-pub fn extract_affine(
93
-    func: &Function,
94
-    val: ValueId,
95
-    ivs: &HashSet<ValueId>,
96
-) -> Option<AffineExpr> {
105
+pub fn extract_affine(func: &Function, val: ValueId, ivs: &HashSet<ValueId>) -> Option<AffineExpr> {
97106
     // Is this an IV?
98107
     if ivs.contains(&val) {
99108
         return Some(AffineExpr::from_iv(val));
@@ -142,13 +151,19 @@ pub fn extract_affine(
142151
 
143152
 fn resolve_const(func: &Function, vid: ValueId) -> Option<i64> {
144153
     let inst = find_inst(func, vid)?;
145
-    if let InstKind::ConstInt(c, _) = &inst.kind { i64::try_from(*c).ok() } else { None }
154
+    if let InstKind::ConstInt(c, _) = &inst.kind {
155
+        i64::try_from(*c).ok()
156
+    } else {
157
+        None
158
+    }
146159
 }
147160
 
148161
 fn find_inst(func: &Function, vid: ValueId) -> Option<&Inst> {
149162
     for block in &func.blocks {
150163
         for inst in &block.insts {
151
-            if inst.id == vid { return Some(inst); }
164
+            if inst.id == vid {
165
+                return Some(inst);
166
+            }
152167
         }
153168
     }
154169
     None
@@ -203,7 +218,12 @@ fn extract_mem_ref(
203218
     // We work with the flat offset (single index for 1D GEP).
204219
     let idx = indices.first()?;
205220
     let subscript = extract_affine(func, *idx, ivs)?;
206
-    Some(MemRef { inst_id, base, subscript, is_write })
221
+    Some(MemRef {
222
+        inst_id,
223
+        base,
224
+        subscript,
225
+        is_write,
226
+    })
207227
 }
208228
 
209229
 // ---------------------------------------------------------------------------
@@ -229,17 +249,23 @@ pub fn test_dependence(ref_a: &MemRef, ref_b: &MemRef) -> DepResult {
229249
     // If the constant is 0, they access the same element (same iteration = ok
230250
     // unless both are writes). If non-zero, they access different elements.
231251
     if diff.terms.is_empty() {
232
-        return DepResult { dependent: diff.constant == 0 };
252
+        return DepResult {
253
+            dependent: diff.constant == 0,
254
+        };
233255
     }
234256
 
235257
     // GCD of all IV coefficients in the difference.
236
-    let g = diff.terms.iter()
258
+    let g = diff
259
+        .terms
260
+        .iter()
237261
         .map(|(c, _)| c.unsigned_abs())
238262
         .fold(0u64, gcd);
239263
 
240264
     if g == 0 {
241265
         // All coefficients are zero — same as fixed-distance case.
242
-        return DepResult { dependent: diff.constant == 0 };
266
+        return DepResult {
267
+            dependent: diff.constant == 0,
268
+        };
243269
     }
244270
 
245271
     // GCD test: if gcd does not divide the constant difference,
@@ -249,7 +275,11 @@ pub fn test_dependence(ref_a: &MemRef, ref_b: &MemRef) -> DepResult {
249275
 }
250276
 
251277
 fn gcd(a: u64, b: u64) -> u64 {
252
-    if b == 0 { a } else { gcd(b, a % b) }
278
+    if b == 0 {
279
+        a
280
+    } else {
281
+        gcd(b, a % b)
282
+    }
253283
 }
254284
 
255285
 // ---------------------------------------------------------------------------
@@ -287,17 +317,26 @@ pub fn fusion_legal(
287317
     let refs_b_raw = collect_mem_refs(func, body_b, &ivs_b);
288318
 
289319
     // Remap iv_b → iv_a in B's subscripts so the comparison works.
290
-    let refs_b: Vec<MemRef> = refs_b_raw.into_iter().map(|mut r| {
291
-        for term in &mut r.subscript.terms {
292
-            if term.1 == iv_b { term.1 = iv_a; }
293
-        }
294
-        r
295
-    }).collect();
320
+    let refs_b: Vec<MemRef> = refs_b_raw
321
+        .into_iter()
322
+        .map(|mut r| {
323
+            for term in &mut r.subscript.terms {
324
+                if term.1 == iv_b {
325
+                    term.1 = iv_a;
326
+                }
327
+            }
328
+            r
329
+        })
330
+        .collect();
296331
 
297332
     for ra in &refs_a {
298333
         for rb in &refs_b {
299
-            if !ra.is_write && !rb.is_write { continue; }
300
-            if ra.base != rb.base { continue; }
334
+            if !ra.is_write && !rb.is_write {
335
+                continue;
336
+            }
337
+            if ra.base != rb.base {
338
+                continue;
339
+            }
301340
 
302341
             let diff = rb.subscript.sub(&ra.subscript);
303342
 
@@ -330,9 +369,13 @@ pub fn interchange_legal(
330369
 
331370
     // For each pair of refs where at least one is a write:
332371
     for i in 0..refs.len() {
333
-        for j in (i+1)..refs.len() {
334
-            if !refs[i].is_write && !refs[j].is_write { continue; }
335
-            if refs[i].base != refs[j].base { continue; }
372
+        for j in (i + 1)..refs.len() {
373
+            if !refs[i].is_write && !refs[j].is_write {
374
+                continue;
375
+            }
376
+            if refs[i].base != refs[j].base {
377
+                continue;
378
+            }
336379
 
337380
             // Both refs share a base and at least one is a write.
338381
             // Check if the subscript difference has non-zero
@@ -370,8 +413,14 @@ mod tests {
370413
     #[test]
371414
     fn affine_add_sub() {
372415
         let iv = ValueId(100);
373
-        let a = AffineExpr { constant: 3, terms: vec![(2, iv)] };
374
-        let b = AffineExpr { constant: 1, terms: vec![(1, iv)] };
416
+        let a = AffineExpr {
417
+            constant: 3,
418
+            terms: vec![(2, iv)],
419
+        };
420
+        let b = AffineExpr {
421
+            constant: 1,
422
+            terms: vec![(1, iv)],
423
+        };
375424
         let sum = a.add(&b);
376425
         assert_eq!(sum.constant, 4);
377426
         assert_eq!(sum.terms.len(), 1);
@@ -386,7 +435,10 @@ mod tests {
386435
     #[test]
387436
     fn affine_scale() {
388437
         let iv = ValueId(100);
389
-        let a = AffineExpr { constant: 2, terms: vec![(3, iv)] };
438
+        let a = AffineExpr {
439
+            constant: 2,
440
+            terms: vec![(3, iv)],
441
+        };
390442
         let scaled = a.scale(4);
391443
         assert_eq!(scaled.constant, 8);
392444
         assert_eq!(scaled.terms[0], (12, iv));
@@ -399,13 +451,21 @@ mod tests {
399451
         // constant = 1 ≠ 0 → independent.
400452
         let iv = ValueId(100);
401453
         let ref_a = MemRef {
402
-            inst_id: ValueId(0), base: ValueId(50),
403
-            subscript: AffineExpr { constant: 1, terms: vec![(2, iv)] },
454
+            inst_id: ValueId(0),
455
+            base: ValueId(50),
456
+            subscript: AffineExpr {
457
+                constant: 1,
458
+                terms: vec![(2, iv)],
459
+            },
404460
             is_write: true,
405461
         };
406462
         let ref_b = MemRef {
407
-            inst_id: ValueId(1), base: ValueId(50),
408
-            subscript: AffineExpr { constant: 2, terms: vec![(2, iv)] },
463
+            inst_id: ValueId(1),
464
+            base: ValueId(50),
465
+            subscript: AffineExpr {
466
+                constant: 2,
467
+                terms: vec![(2, iv)],
468
+            },
409469
             is_write: false,
410470
         };
411471
         let dep = test_dependence(&ref_a, &ref_b);
@@ -417,13 +477,21 @@ mod tests {
417477
         // a(i) vs a(i): same subscript → always dependent.
418478
         let iv = ValueId(100);
419479
         let ref_a = MemRef {
420
-            inst_id: ValueId(0), base: ValueId(50),
421
-            subscript: AffineExpr { constant: 0, terms: vec![(1, iv)] },
480
+            inst_id: ValueId(0),
481
+            base: ValueId(50),
482
+            subscript: AffineExpr {
483
+                constant: 0,
484
+                terms: vec![(1, iv)],
485
+            },
422486
             is_write: true,
423487
         };
424488
         let ref_b = MemRef {
425
-            inst_id: ValueId(1), base: ValueId(50),
426
-            subscript: AffineExpr { constant: 0, terms: vec![(1, iv)] },
489
+            inst_id: ValueId(1),
490
+            base: ValueId(50),
491
+            subscript: AffineExpr {
492
+                constant: 0,
493
+                terms: vec![(1, iv)],
494
+            },
427495
             is_write: false,
428496
         };
429497
         let dep = test_dependence(&ref_a, &ref_b);
@@ -436,33 +504,55 @@ mod tests {
436504
         // (they cancel: 3-3=0). So diff = constant 1, no terms → independent.
437505
         let iv = ValueId(100);
438506
         let ref_a = MemRef {
439
-            inst_id: ValueId(0), base: ValueId(50),
440
-            subscript: AffineExpr { constant: 0, terms: vec![(3, iv)] },
507
+            inst_id: ValueId(0),
508
+            base: ValueId(50),
509
+            subscript: AffineExpr {
510
+                constant: 0,
511
+                terms: vec![(3, iv)],
512
+            },
441513
             is_write: true,
442514
         };
443515
         let ref_b = MemRef {
444
-            inst_id: ValueId(1), base: ValueId(50),
445
-            subscript: AffineExpr { constant: 1, terms: vec![(3, iv)] },
516
+            inst_id: ValueId(1),
517
+            base: ValueId(50),
518
+            subscript: AffineExpr {
519
+                constant: 1,
520
+                terms: vec![(3, iv)],
521
+            },
446522
             is_write: false,
447523
         };
448524
         let dep = test_dependence(&ref_a, &ref_b);
449
-        assert!(!dep.dependent, "a(3i) and a(3i+1) should be independent by GCD test");
525
+        assert!(
526
+            !dep.dependent,
527
+            "a(3i) and a(3i+1) should be independent by GCD test"
528
+        );
450529
     }
451530
 
452531
     #[test]
453532
     fn distinct_bases_independent() {
454533
         let iv = ValueId(100);
455534
         let ref_a = MemRef {
456
-            inst_id: ValueId(0), base: ValueId(50),
457
-            subscript: AffineExpr { constant: 0, terms: vec![(1, iv)] },
535
+            inst_id: ValueId(0),
536
+            base: ValueId(50),
537
+            subscript: AffineExpr {
538
+                constant: 0,
539
+                terms: vec![(1, iv)],
540
+            },
458541
             is_write: true,
459542
         };
460543
         let ref_b = MemRef {
461
-            inst_id: ValueId(1), base: ValueId(60), // different base
462
-            subscript: AffineExpr { constant: 0, terms: vec![(1, iv)] },
544
+            inst_id: ValueId(1),
545
+            base: ValueId(60), // different base
546
+            subscript: AffineExpr {
547
+                constant: 0,
548
+                terms: vec![(1, iv)],
549
+            },
463550
             is_write: false,
464551
         };
465552
         let dep = test_dependence(&ref_a, &ref_b);
466
-        assert!(!dep.dependent, "distinct bases should be independent (Fortran no-alias)");
553
+        assert!(
554
+            !dep.dependent,
555
+            "distinct bases should be independent (Fortran no-alias)"
556
+        );
467557
     }
468558
 }
src/opt/dse.rsmodified
209 lines changed — click to load
@@ -25,8 +25,8 @@
2525
 //! initialization sequences where a variable is zeroed and then
2626
 //! immediately written with the real value.
2727
 
28
-use super::pass::Pass;
2928
 use super::alias::{self, AliasResult};
29
+use super::pass::Pass;
3030
 use crate::ir::inst::*;
3131
 use crate::ir::types::IrType;
3232
 use std::collections::HashSet;
@@ -58,7 +58,10 @@ fn dse_block(func: &mut Function, block_idx: usize) -> bool {
5858
                         }
5959
                     }
6060
                 }
61
-                next_pending.push(PendingStore { ptr: *ptr, inst_idx: i });
61
+                next_pending.push(PendingStore {
62
+                    ptr: *ptr,
63
+                    inst_idx: i,
64
+                });
6265
                 pending = next_pending;
6366
             }
6467
 
@@ -82,18 +85,13 @@ fn dse_block(func: &mut Function, block_idx: usize) -> bool {
8285
                 let pointer_args: Vec<ValueId> = args
8386
                     .iter()
8487
                     .copied()
85
-                    .filter(|arg| {
86
-                        matches!(
87
-                            func.value_type(*arg),
88
-                            Some(IrType::Ptr(_))
89
-                        )
90
-                    })
88
+                    .filter(|arg| matches!(func.value_type(*arg), Some(IrType::Ptr(_))))
9189
                     .collect();
9290
                 if !pointer_args.is_empty() {
9391
                     pending.retain(|entry| {
94
-                        pointer_args.iter().all(|arg| {
95
-                            !alias::may_reach_through_call_arg(func, entry.ptr, *arg)
96
-                        })
92
+                        pointer_args
93
+                            .iter()
94
+                            .all(|arg| !alias::may_reach_through_call_arg(func, entry.ptr, *arg))
9795
                     });
9896
                 }
9997
             }
@@ -136,11 +134,15 @@ fn dse_function(func: &mut Function) -> bool {
136134
 pub struct Dse;
137135
 
138136
 impl Pass for Dse {
139
-    fn name(&self) -> &'static str { "dse" }
137
+    fn name(&self) -> &'static str {
138
+        "dse"
139
+    }
140140
     fn run(&self, module: &mut Module) -> bool {
141141
         let mut changed = false;
142142
         for func in &mut module.functions {
143
-            if dse_function(func) { changed = true; }
143
+            if dse_function(func) {
144
+                changed = true;
145
+            }
144146
         }
145147
         changed
146148
     }
@@ -149,24 +151,39 @@ impl Pass for Dse {
149151
 #[cfg(test)]
150152
 mod tests {
151153
     use super::*;
152
-    use crate::ir::types::{IrType, IntWidth};
153
-    use crate::lexer::{Span, Position};
154
+    use crate::ir::types::{IntWidth, IrType};
155
+    use crate::lexer::{Position, Span};
154156
 
155157
     fn dummy_span() -> Span {
156158
         let p = Position { line: 1, col: 1 };
157
-        Span { start: p, end: p, file_id: 0 }
159
+        Span {
160
+            start: p,
161
+            end: p,
162
+            file_id: 0,
163
+        }
158164
     }
159165
 
160166
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
161167
         let id = f.next_value_id();
162168
         let entry = f.entry;
163
-        f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
169
+        f.block_mut(entry).insts.push(Inst {
170
+            id,
171
+            kind,
172
+            ty,
173
+            span: dummy_span(),
174
+        });
164175
         id
165176
     }
166177
 
167
-    fn ptr_ty() -> IrType { IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))) }
168
-    fn alloca_ty() -> IrType { IrType::Int(IntWidth::I32) }
169
-    fn i32_ty() -> IrType { IrType::Int(IntWidth::I32) }
178
+    fn ptr_ty() -> IrType {
179
+        IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))
180
+    }
181
+    fn alloca_ty() -> IrType {
182
+        IrType::Int(IntWidth::I32)
183
+    }
184
+    fn i32_ty() -> IrType {
185
+        IrType::Int(IntWidth::I32)
186
+    }
170187
 
171188
     /// %ptr = alloca i32
172189
     /// store 1, %ptr
@@ -177,10 +194,10 @@ mod tests {
177194
         let mut m = Module::new("t".into());
178195
         let mut f = Function::new("f".into(), vec![], IrType::Void);
179196
         let ptr = push(&mut f, InstKind::Alloca(alloca_ty()), ptr_ty());
180
-        let v1  = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), i32_ty());
181
-        let v2  = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), i32_ty());
182
-        push(&mut f, InstKind::Store(v1, ptr), IrType::Void);   // dead
183
-        push(&mut f, InstKind::Store(v2, ptr), IrType::Void);   // live
197
+        let v1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), i32_ty());
198
+        let v2 = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), i32_ty());
199
+        push(&mut f, InstKind::Store(v1, ptr), IrType::Void); // dead
200
+        push(&mut f, InstKind::Store(v2, ptr), IrType::Void); // live
184201
         let _loaded = push(&mut f, InstKind::Load(ptr), i32_ty());
185202
         let entry = f.entry;
186203
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
@@ -191,7 +208,10 @@ mod tests {
191208
         let insts = &m.functions[0].blocks[0].insts;
192209
         assert_eq!(insts.len(), 5, "first store should be eliminated");
193210
         // The surviving Store should use v2.
194
-        let stores: Vec<_> = insts.iter().filter(|i| matches!(i.kind, InstKind::Store(..))).collect();
211
+        let stores: Vec<_> = insts
212
+            .iter()
213
+            .filter(|i| matches!(i.kind, InstKind::Store(..)))
214
+            .collect();
195215
         assert_eq!(stores.len(), 1);
196216
         assert!(matches!(stores[0].kind, InstKind::Store(v, _) if v == v2));
197217
     }
@@ -202,7 +222,7 @@ mod tests {
202222
         let mut m = Module::new("t".into());
203223
         let mut f = Function::new("f".into(), vec![], i32_ty());
204224
         let ptr = push(&mut f, InstKind::Alloca(alloca_ty()), ptr_ty());
205
-        let v1  = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), i32_ty());
225
+        let v1 = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), i32_ty());
206226
         push(&mut f, InstKind::Store(v1, ptr), IrType::Void);
207227
         let loaded = push(&mut f, InstKind::Load(ptr), i32_ty());
208228
         let entry = f.entry;
@@ -223,23 +243,35 @@ mod tests {
223243
         let ptr = push(&mut f, InstKind::Alloca(arr_ty), arr_ptr_ty);
224244
         let off0 = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), i32_ty());
225245
         let off1 = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), i32_ty());
226
-        let gep0 = push(&mut f, InstKind::GetElementPtr(ptr, vec![off0]),
227
-            IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))));
228
-        let gep1 = push(&mut f, InstKind::GetElementPtr(ptr, vec![off1]),
229
-            IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))));
246
+        let gep0 = push(
247
+            &mut f,
248
+            InstKind::GetElementPtr(ptr, vec![off0]),
249
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))),
250
+        );
251
+        let gep1 = push(
252
+            &mut f,
253
+            InstKind::GetElementPtr(ptr, vec![off1]),
254
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))),
255
+        );
230256
         let v1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), i32_ty());
231257
         let v2 = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), i32_ty());
232
-        push(&mut f, InstKind::Store(v1, gep0), IrType::Void);  // dead
233
-        push(&mut f, InstKind::Store(v2, gep1), IrType::Void);  // live
258
+        push(&mut f, InstKind::Store(v1, gep0), IrType::Void); // dead
259
+        push(&mut f, InstKind::Store(v2, gep1), IrType::Void); // live
234260
         let entry = f.entry;
235261
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
236262
         m.add_function(f);
237263
 
238264
         assert!(Dse.run(&mut m));
239
-        let stores: Vec<_> = m.functions[0].blocks[0].insts.iter()
265
+        let stores: Vec<_> = m.functions[0].blocks[0]
266
+            .insts
267
+            .iter()
240268
             .filter(|i| matches!(i.kind, InstKind::Store(..)))
241269
             .collect();
242
-        assert_eq!(stores.len(), 1, "must-alias GEP overwrite should kill the first store");
270
+        assert_eq!(
271
+            stores.len(),
272
+            1,
273
+            "must-alias GEP overwrite should kill the first store"
274
+        );
243275
         assert!(matches!(stores[0].kind, InstKind::Store(v, _) if v == v2));
244276
     }
245277
 
@@ -249,12 +281,12 @@ mod tests {
249281
         let mut m = Module::new("t".into());
250282
         let mut f = Function::new("f".into(), vec![], IrType::Void);
251283
         let ptr = push(&mut f, InstKind::Alloca(alloca_ty()), ptr_ty());
252
-        let v1  = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), i32_ty());
253
-        let v2  = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), i32_ty());
254
-        let v3  = push(&mut f, InstKind::ConstInt(3, IntWidth::I32), i32_ty());
255
-        push(&mut f, InstKind::Store(v1, ptr), IrType::Void);  // dead
256
-        push(&mut f, InstKind::Store(v2, ptr), IrType::Void);  // dead
257
-        push(&mut f, InstKind::Store(v3, ptr), IrType::Void);  // live (block exit)
284
+        let v1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), i32_ty());
285
+        let v2 = push(&mut f, InstKind::ConstInt(2, IntWidth::I32), i32_ty());
286
+        let v3 = push(&mut f, InstKind::ConstInt(3, IntWidth::I32), i32_ty());
287
+        push(&mut f, InstKind::Store(v1, ptr), IrType::Void); // dead
288
+        push(&mut f, InstKind::Store(v2, ptr), IrType::Void); // dead
289
+        push(&mut f, InstKind::Store(v3, ptr), IrType::Void); // live (block exit)
258290
         let entry = f.entry;
259291
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
260292
         m.add_function(f);
@@ -263,7 +295,9 @@ mod tests {
263295
         // (stores of v1 and v2 are dead; store of v3 remains because it
264296
         //  might be read in a successor — we don't do cross-block analysis)
265297
         assert!(Dse.run(&mut m));
266
-        let stores: Vec<_> = m.functions[0].blocks[0].insts.iter()
298
+        let stores: Vec<_> = m.functions[0].blocks[0]
299
+            .insts
300
+            .iter()
267301
             .filter(|i| matches!(i.kind, InstKind::Store(..)))
268302
             .collect();
269303
         // Two dead stores removed, one survives.
src/opt/fast_math.rsmodified
96 lines changed — click to load
@@ -24,7 +24,9 @@ use super::util::substitute_uses;
2424
 pub struct FastMathReassoc;
2525
 
2626
 impl Pass for FastMathReassoc {
27
-    fn name(&self) -> &'static str { "fast-math-reassoc" }
27
+    fn name(&self) -> &'static str {
28
+        "fast-math-reassoc"
29
+    }
2830
 
2931
     fn run(&self, module: &mut Module) -> bool {
3032
         let mut changed = false;
@@ -83,7 +85,10 @@ struct SignedFloatConst {
8385
 
8486
 impl SignedFloatConst {
8587
     fn positive(constant: FloatConst) -> Self {
86
-        Self { constant, negative: false }
88
+        Self {
89
+            constant,
90
+            negative: false,
91
+        }
8792
     }
8893
 
8994
     fn negated(self) -> Self {
@@ -221,13 +226,13 @@ fn collect_chain(
221226
         });
222227
     }
223228
 
224
-        let Some(inst) = defs.get(&value) else {
225
-            return Some(AddChain {
226
-                base: Some(value),
227
-                terms: Vec::new(),
228
-                additive_nodes: 0,
229
-            });
230
-        };
229
+    let Some(inst) = defs.get(&value) else {
230
+        return Some(AddChain {
231
+            base: Some(value),
232
+            terms: Vec::new(),
233
+            additive_nodes: 0,
234
+        });
235
+    };
231236
     match inst.kind {
232237
         InstKind::FAdd(lhs, rhs) if inst.ty == IrType::Float(width) => {
233238
             let lhs_chain = collect_chain(defs, lhs, width)?;
@@ -278,7 +283,9 @@ fn const_float_of(
278283
 ) -> Option<FloatConst> {
279284
     let inst = defs.get(&value)?;
280285
     match inst.kind {
281
-        InstKind::ConstFloat(value, inst_width) if inst_width == width => FloatConst::from_value(value, width),
286
+        InstKind::ConstFloat(value, inst_width) if inst_width == width => {
287
+            FloatConst::from_value(value, width)
288
+        }
282289
         _ => None,
283290
     }
284291
 }
@@ -359,13 +366,22 @@ mod tests {
359366
 
360367
     fn span() -> Span {
361368
         let pos = Position { line: 0, col: 0 };
362
-        Span { file_id: 0, start: pos, end: pos }
369
+        Span {
370
+            file_id: 0,
371
+            start: pos,
372
+            end: pos,
373
+        }
363374
     }
364375
 
365376
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
366377
         let id = f.next_value_id();
367378
         let entry = f.entry;
368
-        f.block_mut(entry).insts.push(Inst { id, kind, ty: ty.clone(), span: span() });
379
+        f.block_mut(entry).insts.push(Inst {
380
+            id,
381
+            kind,
382
+            ty: ty.clone(),
383
+            span: span(),
384
+        });
369385
         f.register_type(id, ty);
370386
         id
371387
     }
@@ -408,7 +424,9 @@ mod tests {
408424
         let func = &module.functions[0];
409425
         let insts = &func.blocks[0].insts;
410426
         assert!(
411
-            insts.iter().any(|inst| matches!(inst.kind, InstKind::ConstFloat(v, FloatWidth::F64) if v == 5.0)),
427
+            insts.iter().any(
428
+                |inst| matches!(inst.kind, InstKind::ConstFloat(v, FloatWidth::F64) if v == 5.0)
429
+            ),
412430
             "reassociated chain should materialize a combined constant:\n{:?}",
413431
             insts
414432
         );
@@ -416,7 +434,10 @@ mod tests {
416434
             matches!(func.blocks[0].terminator, Some(Terminator::Return(Some(v))) if v == add2),
417435
             "outer value should stay the return root"
418436
         );
419
-        let outer = insts.iter().find(|inst| inst.id == add2).expect("outer add should remain");
437
+        let outer = insts
438
+            .iter()
439
+            .find(|inst| inst.id == add2)
440
+            .expect("outer add should remain");
420441
         assert!(
421442
             matches!(outer.kind, InstKind::FAdd(ValueId(0), _)),
422443
             "outer add should become x + const, got {:?}",
src/opt/fission.rsmodified
191 lines changed — click to load
@@ -10,24 +10,28 @@
1010
 //!
1111
 //! This avoids SSA domination bugs from selective instruction removal.
1212
 
13
-use std::collections::HashSet;
14
-use crate::ir::inst::*;
15
-use crate::ir::walk::{find_natural_loops, predecessors};
16
-use super::loop_utils::{find_preheader, clone_loop};
1713
 use super::dep_analysis::{collect_mem_refs, test_dependence};
14
+use super::loop_utils::{clone_loop, find_preheader};
1815
 use super::pass::Pass;
16
+use crate::ir::inst::*;
17
+use crate::ir::walk::{find_natural_loops, predecessors};
18
+use std::collections::HashSet;
1919
 
2020
 const FISSION_MIN_BODY: usize = 4;
2121
 
2222
 pub struct LoopFission;
2323
 
2424
 impl Pass for LoopFission {
25
-    fn name(&self) -> &'static str { "loop-fission" }
25
+    fn name(&self) -> &'static str {
26
+        "loop-fission"
27
+    }
2628
 
2729
     fn run(&self, module: &mut Module) -> bool {
2830
         let mut changed = false;
2931
         for func in &mut module.functions {
30
-            if fission_in_function(func) { changed = true; }
32
+            if fission_in_function(func) {
33
+                changed = true;
34
+            }
3135
         }
3236
         changed
3337
     }
@@ -38,12 +42,18 @@ fn fission_in_function(func: &mut Function) -> bool {
3842
     let preds = predecessors(func);
3943
 
4044
     for lp in &loops {
41
-        let Some(_ph_id) = find_preheader(func, lp, &preds) else { continue };
42
-        if lp.latches.len() != 1 { continue; }
45
+        let Some(_ph_id) = find_preheader(func, lp, &preds) else {
46
+            continue;
47
+        };
48
+        if lp.latches.len() != 1 {
49
+            continue;
50
+        }
4351
         let latch_id = lp.latches[0];
4452
 
4553
         let hdr = func.block(lp.header);
46
-        if hdr.params.len() != 1 { continue; }
54
+        if hdr.params.len() != 1 {
55
+            continue;
56
+        }
4757
         let iv = hdr.params[0].id;
4858
 
4959
         // Find the single computation body block.
@@ -51,34 +61,56 @@ fn fission_in_function(func: &mut Function) -> bool {
5161
         let Some(body_bid) = body_block else { continue };
5262
 
5363
         let block = func.block(body_bid);
54
-        if block.insts.len() < FISSION_MIN_BODY { continue; }
64
+        if block.insts.len() < FISSION_MIN_BODY {
65
+            continue;
66
+        }
5567
 
5668
         // Need exactly 2 stores to different arrays.
57
-        let stores: Vec<(usize, ValueId)> = block.insts.iter().enumerate()
69
+        let stores: Vec<(usize, ValueId)> = block
70
+            .insts
71
+            .iter()
72
+            .enumerate()
5873
             .filter(|(_, i)| matches!(i.kind, InstKind::Store(..)))
5974
             .map(|(idx, i)| (idx, i.id))
6075
             .collect();
61
-        if stores.len() != 2 { continue; }
76
+        if stores.len() != 2 {
77
+            continue;
78
+        }
6279
 
6380
         // Check independence via dep analysis.
6481
         let mut ivs = HashSet::new();
6582
         ivs.insert(iv);
6683
         let mem_refs = collect_mem_refs(func, &lp.body, &ivs);
6784
         let writes: Vec<_> = mem_refs.iter().filter(|r| r.is_write).collect();
68
-        if writes.len() != 2 { continue; }
69
-        if writes[0].base == writes[1].base { continue; }
85
+        if writes.len() != 2 {
86
+            continue;
87
+        }
88
+        if writes[0].base == writes[1].base {
89
+            continue;
90
+        }
7091
 
7192
         let mut has_cross_dep = false;
7293
         for i in 0..mem_refs.len() {
73
-            for j in (i+1)..mem_refs.len() {
74
-                if !mem_refs[i].is_write && !mem_refs[j].is_write { continue; }
75
-                if mem_refs[i].base == mem_refs[j].base { continue; }
94
+            for j in (i + 1)..mem_refs.len() {
95
+                if !mem_refs[i].is_write && !mem_refs[j].is_write {
96
+                    continue;
97
+                }
98
+                if mem_refs[i].base == mem_refs[j].base {
99
+                    continue;
100
+                }
76101
                 let dep = test_dependence(&mem_refs[i], &mem_refs[j]);
77
-                if dep.dependent { has_cross_dep = true; break; }
102
+                if dep.dependent {
103
+                    has_cross_dep = true;
104
+                    break;
105
+                }
106
+            }
107
+            if has_cross_dep {
108
+                break;
78109
             }
79
-            if has_cross_dep { break; }
80110
         }
81
-        if has_cross_dep { continue; }
111
+        if has_cross_dep {
112
+            continue;
113
+        }
82114
 
83115
         // Find the exit block.
84116
         let exit_id = find_loop_exit(func, lp);
@@ -104,8 +136,7 @@ fn fission_in_function(func: &mut Function) -> bool {
104136
         };
105137
 
106138
         let bridge = func.create_block("fission_bridge");
107
-        func.block_mut(bridge).terminator =
108
-            Some(Terminator::Branch(clone_header, vec![init_val]));
139
+        func.block_mut(bridge).terminator = Some(Terminator::Branch(clone_header, vec![init_val]));
109140
 
110141
         // Redirect original cmp's exit → bridge.
111142
         for &bid in &lp.body {
@@ -130,7 +161,9 @@ fn fission_in_function(func: &mut Function) -> bool {
130161
 /// making it a dead store that DSE/DCE can clean up.
131162
 fn neutralize_store(func: &mut Function, block_id: BlockId, store_idx: usize) {
132163
     let block = func.block_mut(block_id);
133
-    if store_idx >= block.insts.len() { return; }
164
+    if store_idx >= block.insts.len() {
165
+        return;
166
+    }
134167
     if let InstKind::Store(_, _) = block.insts[store_idx].kind {
135168
         // Replace with a store of undef — the store is now dead.
136169
         // We keep the store instruction (not remove it) to preserve
@@ -152,21 +185,35 @@ fn find_computation_block(
152185
 ) -> Option<BlockId> {
153186
     let mut comp = None;
154187
     for &bid in &lp.body {
155
-        if bid == lp.header || bid == latch_id { continue; }
188
+        if bid == lp.header || bid == latch_id {
189
+            continue;
190
+        }
156191
         let block = func.block(bid);
157
-        if block.insts.iter().any(|i| matches!(i.kind, InstKind::Store(..))) {
158
-            if comp.is_some() { return None; }
192
+        if block
193
+            .insts
194
+            .iter()
195
+            .any(|i| matches!(i.kind, InstKind::Store(..)))
196
+        {
197
+            if comp.is_some() {
198
+                return None;
199
+            }
159200
             comp = Some(bid);
160201
         }
161202
     }
162203
     comp
163204
 }
164205
 
165
-fn backward_slice(func: &Function, root: ValueId, loop_defs: &HashSet<ValueId>) -> HashSet<ValueId> {
206
+fn backward_slice(
207
+    func: &Function,
208
+    root: ValueId,
209
+    loop_defs: &HashSet<ValueId>,
210
+) -> HashSet<ValueId> {
166211
     let mut slice = HashSet::new();
167212
     let mut worklist = vec![root];
168213
     while let Some(vid) = worklist.pop() {
169
-        if !slice.insert(vid) { continue; }
214
+        if !slice.insert(vid) {
215
+            continue;
216
+        }
170217
         for block in &func.blocks {
171218
             for inst in &block.insts {
172219
                 if inst.id == vid {
@@ -186,7 +233,9 @@ fn find_loop_exit(func: &Function, lp: &crate::ir::walk::NaturalLoop) -> Option<
186233
     for &bid in &lp.body {
187234
         let block = func.block(bid);
188235
         if let Some(Terminator::CondBranch { false_dest, .. }) = &block.terminator {
189
-            if !lp.body.contains(false_dest) { return Some(*false_dest); }
236
+            if !lp.body.contains(false_dest) {
237
+                return Some(*false_dest);
238
+            }
190239
         }
191240
     }
192241
     None
src/opt/fusion.rsmodified
301 lines changed — click to load
@@ -9,23 +9,27 @@
99
 //!
1010
 //! This avoids splicing instructions between blocks entirely.
1111
 
12
-use std::collections::HashSet;
13
-use crate::ir::inst::*;
14
-use crate::ir::walk::{find_natural_loops, predecessors};
12
+use super::dep_analysis;
1513
 use super::loop_utils::remap_inst_kind;
1614
 use super::loop_utils::{find_preheader, resolve_const_int};
17
-use super::dep_analysis;
1815
 use super::pass::Pass;
16
+use crate::ir::inst::*;
17
+use crate::ir::walk::{find_natural_loops, predecessors};
18
+use std::collections::HashSet;
1919
 
2020
 pub struct LoopFusion;
2121
 
2222
 impl Pass for LoopFusion {
23
-    fn name(&self) -> &'static str { "loop-fusion" }
23
+    fn name(&self) -> &'static str {
24
+        "loop-fusion"
25
+    }
2426
 
2527
     fn run(&self, module: &mut Module) -> bool {
2628
         let mut changed = false;
2729
         for func in &mut module.functions {
28
-            if fusion_in_function(func) { changed = true; }
30
+            if fusion_in_function(func) {
31
+                changed = true;
32
+            }
2933
         }
3034
         changed
3135
     }
@@ -33,63 +37,99 @@ impl Pass for LoopFusion {
3337
 
3438
 fn fusion_in_function(func: &mut Function) -> bool {
3539
     let loops = find_natural_loops(func);
36
-    if loops.len() < 2 { return false; }
40
+    if loops.len() < 2 {
41
+        return false;
42
+    }
3743
     let preds = predecessors(func);
3844
 
3945
     for i in 0..loops.len() {
40
-        for j in (i+1)..loops.len() {
46
+        for j in (i + 1)..loops.len() {
4147
             let lp_a = &loops[i];
4248
             let lp_b = &loops[j];
4349
 
4450
             // Both need preheaders and single latches.
45
-            let Some(_ph_a) = find_preheader(func, lp_a, &preds) else { continue };
46
-            let Some(ph_b) = find_preheader(func, lp_b, &preds) else { continue };
47
-            if lp_a.latches.len() != 1 || lp_b.latches.len() != 1 { continue; }
51
+            let Some(_ph_a) = find_preheader(func, lp_a, &preds) else {
52
+                continue;
53
+            };
54
+            let Some(ph_b) = find_preheader(func, lp_b, &preds) else {
55
+                continue;
56
+            };
57
+            if lp_a.latches.len() != 1 || lp_b.latches.len() != 1 {
58
+                continue;
59
+            }
4860
             let latch_a = lp_a.latches[0];
4961
             let latch_b = lp_b.latches[0];
5062
 
5163
             // Both headers must have exactly 1 block param (IV).
5264
             let hdr_a = func.block(lp_a.header);
5365
             let hdr_b = func.block(lp_b.header);
54
-            if hdr_a.params.len() != 1 || hdr_b.params.len() != 1 { continue; }
66
+            if hdr_a.params.len() != 1 || hdr_b.params.len() != 1 {
67
+                continue;
68
+            }
5569
             let iv_a = hdr_a.params[0].id;
5670
             let iv_b = hdr_b.params[0].id;
5771
 
5872
             // Neither loop should be nested inside the other.
59
-            if lp_a.body.iter().any(|b| lp_b.body.contains(b)) { continue; }
60
-            if lp_b.body.iter().any(|b| lp_a.body.contains(b)) { continue; }
73
+            if lp_a.body.iter().any(|b| lp_b.body.contains(b)) {
74
+                continue;
75
+            }
76
+            if lp_b.body.iter().any(|b| lp_a.body.contains(b)) {
77
+                continue;
78
+            }
6179
 
6280
             // Neither loop should contain inner loops. Fusing loops
6381
             // with nested inner loops requires more complex handling
6482
             // (inner loop blocks need reparenting). V1: simple only.
65
-            let has_inner_a = loops.iter().any(|other|
66
-                other.header != lp_a.header && lp_a.body.is_superset(&other.body));
67
-            let has_inner_b = loops.iter().any(|other|
68
-                other.header != lp_b.header && lp_b.body.is_superset(&other.body));
69
-            if has_inner_a || has_inner_b { continue; }
83
+            let has_inner_a = loops
84
+                .iter()
85
+                .any(|other| other.header != lp_a.header && lp_a.body.is_superset(&other.body));
86
+            let has_inner_b = loops
87
+                .iter()
88
+                .any(|other| other.header != lp_b.header && lp_b.body.is_superset(&other.body));
89
+            if has_inner_a || has_inner_b {
90
+                continue;
91
+            }
7092
 
7193
             // Skip loops produced by fission in the same pipeline
7294
             // iteration — they have clone/bridge blocks that fusion
7395
             // can't handle safely.
74
-            let has_clone_a = lp_a.body.iter().any(|&b|
75
-                func.block(b).name.contains("clone") || func.block(b).name.contains("fission"));
76
-            let has_clone_b = lp_b.body.iter().any(|&b|
77
-                func.block(b).name.contains("clone") || func.block(b).name.contains("fission"));
78
-            if has_clone_a || has_clone_b { continue; }
96
+            let has_clone_a = lp_a.body.iter().any(|&b| {
97
+                func.block(b).name.contains("clone") || func.block(b).name.contains("fission")
98
+            });
99
+            let has_clone_b = lp_b.body.iter().any(|&b| {
100
+                func.block(b).name.contains("clone") || func.block(b).name.contains("fission")
101
+            });
102
+            if has_clone_a || has_clone_b {
103
+                continue;
104
+            }
79105
 
80106
             // Loop A's exit must be (or flow to) loop B's preheader.
81107
             let exit_a = find_loop_exit(func, lp_a);
82108
             let Some(exit_a) = exit_a else { continue };
83
-            if exit_a != ph_b && !flows_to(func, exit_a, ph_b) { continue; }
109
+            if exit_a != ph_b && !flows_to(func, exit_a, ph_b) {
110
+                continue;
111
+            }
84112
 
85113
             // Matching iteration spaces.
86
-            let Some(init_a) = get_init_const(func, lp_a, &preds) else { continue };
87
-            let Some(init_b) = get_init_const(func, lp_b, &preds) else { continue };
88
-            if init_a != init_b { continue; }
114
+            let Some(init_a) = get_init_const(func, lp_a, &preds) else {
115
+                continue;
116
+            };
117
+            let Some(init_b) = get_init_const(func, lp_b, &preds) else {
118
+                continue;
119
+            };
120
+            if init_a != init_b {
121
+                continue;
122
+            }
89123
 
90
-            let Some(bound_a) = find_bound_const(func, lp_a, iv_a) else { continue };
91
-            let Some(bound_b) = find_bound_const(func, lp_b, iv_b) else { continue };
92
-            if bound_a != bound_b { continue; }
124
+            let Some(bound_a) = find_bound_const(func, lp_a, iv_a) else {
125
+                continue;
126
+            };
127
+            let Some(bound_b) = find_bound_const(func, lp_b, iv_b) else {
128
+                continue;
129
+            };
130
+            if bound_a != bound_b {
131
+                continue;
132
+            }
93133
 
94134
             // Dep analysis: fusion legal?
95135
             if !dep_analysis::fusion_legal(func, &lp_a.body, &lp_b.body, iv_a, iv_b) {
@@ -123,11 +163,7 @@ fn fusion_in_function(func: &mut Function) -> bool {
123163
 
124164
             // ---- Perform fusion via latch redirect ----
125165
             do_fusion_latch_redirect(
126
-                func, lp_a, lp_b,
127
-                latch_a, latch_b,
128
-                iv_a, iv_b,
129
-                body_b_id, cmp_b_id,
130
-                exit_a, exit_b,
166
+                func, lp_a, lp_b, latch_a, latch_b, iv_a, iv_b, body_b_id, cmp_b_id, exit_a, exit_b,
131167
             );
132168
             return true;
133169
         }
@@ -158,10 +194,16 @@ fn do_fusion_latch_redirect(
158194
     sub_map.insert(iv_b, iv_a);
159195
     for &bid in &lp_b.body {
160196
         let old_insts: Vec<Inst> = func.block(bid).insts.clone();
161
-        let new_insts: Vec<Inst> = old_insts.into_iter().map(|inst| {
162
-            let new_kind = remap_inst_kind(&inst.kind, &sub_map);
163
-            Inst { kind: new_kind, ..inst }
164
-        }).collect();
197
+        let new_insts: Vec<Inst> = old_insts
198
+            .into_iter()
199
+            .map(|inst| {
200
+                let new_kind = remap_inst_kind(&inst.kind, &sub_map);
201
+                Inst {
202
+                    kind: new_kind,
203
+                    ..inst
204
+                }
205
+            })
206
+            .collect();
165207
         func.block_mut(bid).insts = new_insts;
166208
         // Also remap terminator operands.
167209
         let old_term = func.block(bid).terminator.clone();
@@ -210,7 +252,9 @@ fn do_fusion_latch_redirect(
210252
 
211253
     // Find the block that branches to latch_a (A's body exit).
212254
     let a_body_exit = find_branch_to(func, lp_a, latch_a);
213
-    let Some(a_body_exit_id) = a_body_exit else { return };
255
+    let Some(a_body_exit_id) = a_body_exit else {
256
+        return;
257
+    };
214258
 
215259
     // Redirect A's body exit → B's body.
216260
     redirect_branch(func, a_body_exit_id, latch_a, body_b_id);
@@ -220,8 +264,7 @@ fn do_fusion_latch_redirect(
220264
     // But B's latch's iv_next_b should be discarded — A's latch will
221265
     // compute iv_next_a. So B's latch should just branch to A's latch
222266
     // with no args.
223
-    func.block_mut(latch_b).terminator =
224
-        Some(Terminator::Branch(latch_a, vec![]));
267
+    func.block_mut(latch_b).terminator = Some(Terminator::Branch(latch_a, vec![]));
225268
 
226269
     // Step 3: A's cmp exit (exit_a) should now go to B's exit (exit_b)
227270
     // since B's header/cmp are bypassed. Copy B's exit block content
@@ -235,7 +278,9 @@ fn do_fusion_latch_redirect(
235278
     func.block_mut(lp_b.header).terminator = Some(Terminator::Unreachable);
236279
     // Mark B's cmp blocks too.
237280
     for &bid in &lp_b.body {
238
-        if bid == body_b_id || bid == latch_b { continue; }
281
+        if bid == body_b_id || bid == latch_b {
282
+            continue;
283
+        }
239284
         func.block_mut(bid).terminator = Some(Terminator::Unreachable);
240285
     }
241286
 
@@ -248,7 +293,9 @@ fn find_branch_to(
248293
     target: BlockId,
249294
 ) -> Option<BlockId> {
250295
     for &bid in &lp.body {
251
-        if bid == target { continue; }
296
+        if bid == target {
297
+            continue;
298
+        }
252299
         let block = func.block(bid);
253300
         match &block.terminator {
254301
             Some(Terminator::Branch(dest, _)) if *dest == target => return Some(bid),
@@ -272,7 +319,9 @@ fn find_loop_exit(func: &Function, lp: &crate::ir::walk::NaturalLoop) -> Option<
272319
     for &bid in &lp.body {
273320
         let block = func.block(bid);
274321
         if let Some(Terminator::CondBranch { false_dest, .. }) = &block.terminator {
275
-            if !lp.body.contains(false_dest) { return Some(*false_dest); }
322
+            if !lp.body.contains(false_dest) {
323
+                return Some(*false_dest);
324
+            }
276325
         }
277326
     }
278327
     None
@@ -282,7 +331,9 @@ fn flows_to(func: &Function, from: BlockId, to: BlockId) -> bool {
282331
     let block = func.block(from);
283332
     match &block.terminator {
284333
         Some(Terminator::Branch(dest, _)) => {
285
-            if *dest == to { return true; }
334
+            if *dest == to {
335
+                return true;
336
+            }
286337
             let mid = func.block(*dest);
287338
             if let Some(Terminator::Branch(dest2, _)) = &mid.terminator {
288339
                 return *dest2 == to;
@@ -306,12 +357,22 @@ fn get_init_const(
306357
     resolve_const_int(func, init_val)
307358
 }
308359
 
309
-fn find_bound_const(func: &Function, lp: &crate::ir::walk::NaturalLoop, iv: ValueId) -> Option<i64> {
360
+fn find_bound_const(
361
+    func: &Function,
362
+    lp: &crate::ir::walk::NaturalLoop,
363
+    iv: ValueId,
364
+) -> Option<i64> {
310365
     for &bid in &lp.body {
311366
         let block = func.block(bid);
312367
         for inst in &block.insts {
313368
             if let InstKind::ICmp(_, a, b) = &inst.kind {
314
-                let bound_val = if *a == iv { *b } else if *b == iv { *a } else { continue };
369
+                let bound_val = if *a == iv {
370
+                    *b
371
+                } else if *b == iv {
372
+                    *a
373
+                } else {
374
+                    continue;
375
+                };
315376
                 return resolve_const_int(func, bound_val);
316377
             }
317378
         }
@@ -325,9 +386,15 @@ fn find_body_block(
325386
     latch_id: BlockId,
326387
 ) -> Option<BlockId> {
327388
     for &bid in &lp.body {
328
-        if bid == lp.header || bid == latch_id { continue; }
389
+        if bid == lp.header || bid == latch_id {
390
+            continue;
391
+        }
329392
         let block = func.block(bid);
330
-        if block.insts.iter().any(|i| matches!(i.kind, InstKind::Store(..))) {
393
+        if block
394
+            .insts
395
+            .iter()
396
+            .any(|i| matches!(i.kind, InstKind::Store(..)))
397
+        {
331398
             return Some(bid);
332399
         }
333400
     }
@@ -337,7 +404,11 @@ fn find_body_block(
337404
 fn find_cmp_block(func: &Function, lp: &crate::ir::walk::NaturalLoop) -> Option<BlockId> {
338405
     for &bid in &lp.body {
339406
         let block = func.block(bid);
340
-        if block.insts.iter().any(|i| matches!(i.kind, InstKind::ICmp(..))) {
407
+        if block
408
+            .insts
409
+            .iter()
410
+            .any(|i| matches!(i.kind, InstKind::ICmp(..)))
411
+        {
341412
             return Some(bid);
342413
         }
343414
     }
src/opt/global_lsf.rsmodified
115 lines changed — click to load
@@ -12,22 +12,26 @@
1212
 //!     %r = load %ptr        → %r = %val (forwarded)
1313
 //! ```
1414
 
15
-use std::collections::{HashMap, HashSet, VecDeque};
15
+use super::alias::{self, AliasResult};
16
+use super::pass::Pass;
1617
 use crate::ir::inst::*;
1718
 use crate::ir::types::IrType;
1819
 use crate::ir::walk::{compute_immediate_dominators, predecessors, terminator_targets};
19
-use super::alias::{self, AliasResult};
20
-use super::pass::Pass;
20
+use std::collections::{HashMap, HashSet, VecDeque};
2121
 
2222
 pub struct GlobalLsf;
2323
 
2424
 impl Pass for GlobalLsf {
25
-    fn name(&self) -> &'static str { "global-lsf" }
25
+    fn name(&self) -> &'static str {
26
+        "global-lsf"
27
+    }
2628
 
2729
     fn run(&self, module: &mut Module) -> bool {
2830
         let mut changed = false;
2931
         for func in &mut module.functions {
30
-            if global_lsf_function(func) { changed = true; }
32
+            if global_lsf_function(func) {
33
+                changed = true;
34
+            }
3135
         }
3236
         changed
3337
     }
@@ -51,7 +55,9 @@ fn global_lsf_function(func: &mut Function) -> bool {
5155
         }
5256
     }
5357
 
54
-    if replacements.is_empty() { return false; }
58
+    if replacements.is_empty() {
59
+        return false;
60
+    }
5561
 
5662
     // Apply replacements.
5763
     for block in &mut func.blocks {
@@ -59,11 +65,8 @@ fn global_lsf_function(func: &mut Function) -> bool {
5965
             inst.kind = super::loop_utils::remap_inst_kind(&inst.kind, &replacements);
6066
         }
6167
         if let Some(ref mut term) = block.terminator {
62
-            let new_term = super::loop_utils::remap_terminator(
63
-                term,
64
-                &HashMap::new(),
65
-                &replacements,
66
-            );
68
+            let new_term =
69
+                super::loop_utils::remap_terminator(term, &HashMap::new(), &replacements);
6770
             *term = new_term;
6871
         }
6972
     }
@@ -95,7 +98,9 @@ fn find_reaching_store(
9598
 
9699
     let mut current = load_block;
97100
     while let Some(&idom) = idoms.get(&current) {
98
-        if idom == current { break; } // entry
101
+        if idom == current {
102
+            break;
103
+        } // entry
99104
         current = idom;
100105
 
101106
         if !paths_to_load_are_clean(func, preds, current, load_block, load_ptr) {
@@ -186,9 +191,10 @@ fn update_memory_state(
186191
                 .copied()
187192
                 .filter(|arg| value_is_pointer(func, *arg))
188193
                 .collect();
189
-            if pointer_args.iter().any(|arg| {
190
-                alias::may_reach_through_call_arg(func, load_ptr, *arg)
191
-            }) {
194
+            if pointer_args
195
+                .iter()
196
+                .any(|arg| alias::may_reach_through_call_arg(func, load_ptr, *arg))
197
+            {
192198
                 *last_store = None;
193199
                 *clobbered = true;
194200
             }
@@ -201,10 +207,17 @@ fn value_is_pointer(func: &Function, value: ValueId) -> bool {
201207
     if matches!(func.value_type(value), Some(IrType::Ptr(_))) {
202208
         return true;
203209
     }
204
-    if func.params.iter().any(|param| param.id == value && matches!(param.ty, IrType::Ptr(_))) {
210
+    if func
211
+        .params
212
+        .iter()
213
+        .any(|param| param.id == value && matches!(param.ty, IrType::Ptr(_)))
214
+    {
205215
         return true;
206216
     }
207
-    func.blocks.iter().flat_map(|block| block.insts.iter()).find(|inst| inst.id == value)
217
+    func.blocks
218
+        .iter()
219
+        .flat_map(|block| block.insts.iter())
220
+        .find(|inst| inst.id == value)
208221
         .map(|inst| matches!(inst.ty, IrType::Ptr(_)))
209222
         .unwrap_or(false)
210223
 }
@@ -316,7 +329,7 @@ fn reverse_reachable_blocks(
316329
 #[cfg(test)]
317330
 mod tests {
318331
     use super::*;
319
-    use crate::ir::types::{IrType, IntWidth};
332
+    use crate::ir::types::{IntWidth, IrType};
320333
     use crate::opt::pass::Pass;
321334
 
322335
     #[test]
@@ -379,7 +392,10 @@ mod tests {
379392
         m.add_function(f);
380393
 
381394
         let pass = GlobalLsf;
382
-        assert!(pass.run(&mut m), "straight-line dominated load should be forwarded");
395
+        assert!(
396
+            pass.run(&mut m),
397
+            "straight-line dominated load should be forwarded"
398
+        );
383399
         let term = m.functions[0].block(load_block).terminator.clone().unwrap();
384400
         assert!(
385401
             matches!(term, Terminator::Return(Some(v)) if v == value),
src/opt/gvn.rsmodified
751 lines changed — click to load
@@ -8,16 +8,18 @@
88
 //!
99
 //! Uses the same canonical Key structure as local CSE (cse.rs).
1010
 
11
-use std::collections::HashMap;
11
+use super::pass::Pass;
1212
 use crate::ir::inst::*;
1313
 use crate::ir::types::IrType;
1414
 use crate::ir::walk::{compute_immediate_dominators, dominator_tree_children};
15
-use super::pass::Pass;
15
+use std::collections::HashMap;
1616
 
1717
 pub struct Gvn;
1818
 
1919
 impl Pass for Gvn {
20
-    fn name(&self) -> &'static str { "gvn" }
20
+    fn name(&self) -> &'static str {
21
+        "gvn"
22
+    }
2123
 
2224
     fn run(&self, module: &mut Module) -> bool {
2325
         let pure_calls: Vec<PureCallPolicy> = module
@@ -27,7 +29,9 @@ impl Pass for Gvn {
2729
             .collect();
2830
         let mut changed = false;
2931
         for func in &mut module.functions {
30
-            if gvn_function(func, &pure_calls) { changed = true; }
32
+            if gvn_function(func, &pure_calls) {
33
+                changed = true;
34
+            }
3135
         }
3236
         changed
3337
     }
@@ -58,11 +62,17 @@ struct PureCallPolicy {
5862
 
5963
 impl PureCallPolicy {
6064
     fn for_function(func: &Function) -> Self {
61
-        let arg_policies = func.params.iter().map(|param| classify_pure_arg(func, param)).collect::<Vec<_>>();
65
+        let arg_policies = func
66
+            .params
67
+            .iter()
68
+            .map(|param| classify_pure_arg(func, param))
69
+            .collect::<Vec<_>>();
6270
         let reusable = func.is_pure
6371
             && !matches!(func.return_type, IrType::Void)
6472
             && !func.return_type.is_ptr()
65
-            && arg_policies.iter().all(|policy| *policy != PureArgPolicy::Unsupported)
73
+            && arg_policies
74
+                .iter()
75
+                .all(|policy| *policy != PureArgPolicy::Unsupported)
6676
             && !reads_non_argument_memory(func);
6777
         Self {
6878
             reusable,
@@ -255,10 +265,7 @@ fn wrapper_alloca_values(
255265
                         }
256266
                         let valid_arg = args.iter().enumerate().any(|(arg_idx, arg)| {
257267
                             *arg == alloca_id
258
-                                && policy
259
-                                    .arg_policies
260
-                                    .get(arg_idx)
261
-                                    .copied()
268
+                                && policy.arg_policies.get(arg_idx).copied()
262269
                                     == Some(PureArgPolicy::ReadOnlyWrapperPtr)
263270
                         });
264271
                         if !valid_arg {
@@ -300,32 +307,48 @@ fn key_of(
300307
     wrapper_values: &HashMap<ValueId, ValueId>,
301308
 ) -> Option<Key> {
302309
     let mk = |tag: u32, ops: Vec<ValueId>, aux: i128| -> Option<Key> {
303
-        Some(Key { tag, operands: ops, aux, name: None, ty: inst.ty.clone() })
310
+        Some(Key {
311
+            tag,
312
+            operands: ops,
313
+            aux,
314
+            name: None,
315
+            ty: inst.ty.clone(),
316
+        })
304317
     };
305318
     let mk_named = |tag: u32, name: String| -> Option<Key> {
306
-        Some(Key { tag, operands: vec![], aux: 0, name: Some(name), ty: inst.ty.clone() })
319
+        Some(Key {
320
+            tag,
321
+            operands: vec![],
322
+            aux: 0,
323
+            name: Some(name),
324
+            ty: inst.ty.clone(),
325
+        })
307326
     };
308327
     let remap = |v: ValueId| resolve_value(replacements, v);
309328
     fn canon(a: ValueId, b: ValueId) -> Vec<ValueId> {
310
-        if a.0 <= b.0 { vec![a, b] } else { vec![b, a] }
329
+        if a.0 <= b.0 {
330
+            vec![a, b]
331
+        } else {
332
+            vec![b, a]
333
+        }
311334
     }
312335
 
313336
     match &inst.kind {
314337
         // Pure arithmetic — commutative ops get canonicalized operand order.
315
-        InstKind::IAdd(a, b)  => mk(1, canon(remap(*a), remap(*b)), 0),
316
-        InstKind::ISub(a, b)  => mk(2, vec![remap(*a), remap(*b)], 0),
317
-        InstKind::IMul(a, b)  => mk(3, canon(remap(*a), remap(*b)), 0),
318
-        InstKind::IDiv(a, b)  => mk(4, vec![remap(*a), remap(*b)], 0),
319
-        InstKind::IMod(a, b)  => mk(5, vec![remap(*a), remap(*b)], 0),
320
-        InstKind::INeg(a)     => mk(6, vec![remap(*a)], 0),
321
-        InstKind::FAdd(a, b)  => mk(10, canon(remap(*a), remap(*b)), 0),
322
-        InstKind::FSub(a, b)  => mk(11, vec![remap(*a), remap(*b)], 0),
323
-        InstKind::FMul(a, b)  => mk(12, canon(remap(*a), remap(*b)), 0),
324
-        InstKind::FDiv(a, b)  => mk(13, vec![remap(*a), remap(*b)], 0),
325
-        InstKind::FNeg(a)     => mk(14, vec![remap(*a)], 0),
326
-        InstKind::FAbs(a)     => mk(15, vec![remap(*a)], 0),
327
-        InstKind::FSqrt(a)    => mk(16, vec![remap(*a)], 0),
328
-        InstKind::FPow(a, b)  => mk(17, vec![remap(*a), remap(*b)], 0),
338
+        InstKind::IAdd(a, b) => mk(1, canon(remap(*a), remap(*b)), 0),
339
+        InstKind::ISub(a, b) => mk(2, vec![remap(*a), remap(*b)], 0),
340
+        InstKind::IMul(a, b) => mk(3, canon(remap(*a), remap(*b)), 0),
341
+        InstKind::IDiv(a, b) => mk(4, vec![remap(*a), remap(*b)], 0),
342
+        InstKind::IMod(a, b) => mk(5, vec![remap(*a), remap(*b)], 0),
343
+        InstKind::INeg(a) => mk(6, vec![remap(*a)], 0),
344
+        InstKind::FAdd(a, b) => mk(10, canon(remap(*a), remap(*b)), 0),
345
+        InstKind::FSub(a, b) => mk(11, vec![remap(*a), remap(*b)], 0),
346
+        InstKind::FMul(a, b) => mk(12, canon(remap(*a), remap(*b)), 0),
347
+        InstKind::FDiv(a, b) => mk(13, vec![remap(*a), remap(*b)], 0),
348
+        InstKind::FNeg(a) => mk(14, vec![remap(*a)], 0),
349
+        InstKind::FAbs(a) => mk(15, vec![remap(*a)], 0),
350
+        InstKind::FSqrt(a) => mk(16, vec![remap(*a)], 0),
351
+        InstKind::FPow(a, b) => mk(17, vec![remap(*a), remap(*b)], 0),
329352
         InstKind::ICmp(op, a, b) => {
330353
             let op_val = *op as i128;
331354
             match op {
@@ -335,30 +358,34 @@ fn key_of(
335358
         }
336359
         InstKind::FCmp(op, a, b) => mk(21, vec![remap(*a), remap(*b)], *op as i128),
337360
         InstKind::And(a, b) => mk(30, canon(remap(*a), remap(*b)), 0),
338
-        InstKind::Or(a, b)  => mk(31, canon(remap(*a), remap(*b)), 0),
339
-        InstKind::Not(a)    => mk(32, vec![remap(*a)], 0),
361
+        InstKind::Or(a, b) => mk(31, canon(remap(*a), remap(*b)), 0),
362
+        InstKind::Not(a) => mk(32, vec![remap(*a)], 0),
340363
         InstKind::Select(c, t, f) => mk(33, vec![remap(*c), remap(*t), remap(*f)], 0),
341
-        InstKind::BitAnd(a, b)  => mk(40, canon(remap(*a), remap(*b)), 0),
342
-        InstKind::BitOr(a, b)   => mk(41, canon(remap(*a), remap(*b)), 0),
343
-        InstKind::BitXor(a, b)  => mk(42, canon(remap(*a), remap(*b)), 0),
344
-        InstKind::BitNot(a)     => mk(43, vec![remap(*a)], 0),
345
-        InstKind::Shl(a, b)     => mk(44, vec![remap(*a), remap(*b)], 0),
346
-        InstKind::LShr(a, b)    => mk(45, vec![remap(*a), remap(*b)], 0),
347
-        InstKind::AShr(a, b)    => mk(46, vec![remap(*a), remap(*b)], 0),
348
-        InstKind::CountLeadingZeros(a)  => mk(47, vec![remap(*a)], 0),
364
+        InstKind::BitAnd(a, b) => mk(40, canon(remap(*a), remap(*b)), 0),
365
+        InstKind::BitOr(a, b) => mk(41, canon(remap(*a), remap(*b)), 0),
366
+        InstKind::BitXor(a, b) => mk(42, canon(remap(*a), remap(*b)), 0),
367
+        InstKind::BitNot(a) => mk(43, vec![remap(*a)], 0),
368
+        InstKind::Shl(a, b) => mk(44, vec![remap(*a), remap(*b)], 0),
369
+        InstKind::LShr(a, b) => mk(45, vec![remap(*a), remap(*b)], 0),
370
+        InstKind::AShr(a, b) => mk(46, vec![remap(*a), remap(*b)], 0),
371
+        InstKind::CountLeadingZeros(a) => mk(47, vec![remap(*a)], 0),
349372
         InstKind::CountTrailingZeros(a) => mk(48, vec![remap(*a)], 0),
350
-        InstKind::PopCount(a)           => mk(49, vec![remap(*a)], 0),
373
+        InstKind::PopCount(a) => mk(49, vec![remap(*a)], 0),
351374
         // Conversions.
352
-        InstKind::IntToFloat(a, w)   => mk(50, vec![remap(*a)], w.bits() as i128),
353
-        InstKind::FloatToInt(a, w)   => mk(51, vec![remap(*a)], w.bits() as i128),
354
-        InstKind::FloatExtend(a, w)  => mk(52, vec![remap(*a)], w.bits() as i128),
355
-        InstKind::FloatTrunc(a, w)   => mk(53, vec![remap(*a)], w.bits() as i128),
356
-        InstKind::IntExtend(a, w, s) => mk(54, vec![remap(*a)], (w.bits() as i128) * if *s { 1 } else { -1 }),
357
-        InstKind::IntTrunc(a, w)     => mk(55, vec![remap(*a)], w.bits() as i128),
358
-        InstKind::PtrToInt(a)        => mk(56, vec![remap(*a)], 0),
359
-        InstKind::IntToPtr(a, _)     => mk(57, vec![remap(*a)], 0),
375
+        InstKind::IntToFloat(a, w) => mk(50, vec![remap(*a)], w.bits() as i128),
376
+        InstKind::FloatToInt(a, w) => mk(51, vec![remap(*a)], w.bits() as i128),
377
+        InstKind::FloatExtend(a, w) => mk(52, vec![remap(*a)], w.bits() as i128),
378
+        InstKind::FloatTrunc(a, w) => mk(53, vec![remap(*a)], w.bits() as i128),
379
+        InstKind::IntExtend(a, w, s) => mk(
380
+            54,
381
+            vec![remap(*a)],
382
+            (w.bits() as i128) * if *s { 1 } else { -1 },
383
+        ),
384
+        InstKind::IntTrunc(a, w) => mk(55, vec![remap(*a)], w.bits() as i128),
385
+        InstKind::PtrToInt(a) => mk(56, vec![remap(*a)], 0),
386
+        InstKind::IntToPtr(a, _) => mk(57, vec![remap(*a)], 0),
360387
         // Constants.
361
-        InstKind::ConstInt(v, w)   => {
388
+        InstKind::ConstInt(v, w) => {
362389
             let bits = w.bits();
363390
             let signed = if bits >= 128 {
364391
                 *v
@@ -369,7 +396,7 @@ fn key_of(
369396
             mk(60, vec![], signed)
370397
         }
371398
         InstKind::ConstFloat(v, w) => mk(61, vec![], ((*v).to_bits() as i128) ^ (w.bits() as i128)),
372
-        InstKind::ConstBool(v)     => mk(62, vec![], *v as i128),
399
+        InstKind::ConstBool(v) => mk(62, vec![], *v as i128),
373400
         // GlobalAddr.
374401
         InstKind::GlobalAddr(name) => mk_named(70, name.clone()),
375402
         // GEP.
@@ -403,10 +430,15 @@ fn key_of(
403430
             mk(90, ops, *idx as i128)
404431
         }
405432
         // Impure: loads, stores, runtime calls, external calls, alloca — not GVN candidates.
406
-        InstKind::Load(..) | InstKind::Store(..) | InstKind::Alloca(..)
407
-        | InstKind::Call(..) | InstKind::RuntimeCall(..)
408
-        | InstKind::ConstString(..) | InstKind::Undef(..)
409
-        | InstKind::ExtractField(..) | InstKind::InsertField(..) => None,
433
+        InstKind::Load(..)
434
+        | InstKind::Store(..)
435
+        | InstKind::Alloca(..)
436
+        | InstKind::Call(..)
437
+        | InstKind::RuntimeCall(..)
438
+        | InstKind::ConstString(..)
439
+        | InstKind::Undef(..)
440
+        | InstKind::ExtractField(..)
441
+        | InstKind::InsertField(..) => None,
410442
     }
411443
 }
412444
 
@@ -460,7 +492,9 @@ fn gvn_function(func: &mut Function, pure_calls: &[PureCallPolicy]) -> bool {
460492
         }
461493
     }
462494
 
463
-    if replacements.is_empty() { return false; }
495
+    if replacements.is_empty() {
496
+        return false;
497
+    }
464498
 
465499
     // Apply replacements: substitute all uses of redundant values, then
466500
     // drop the now-dead duplicate instructions directly. This matters
@@ -470,7 +504,9 @@ fn gvn_function(func: &mut Function, pure_calls: &[PureCallPolicy]) -> bool {
470504
         for inst in &mut block.insts {
471505
             inst.kind = remap_operands(&inst.kind, &replacements);
472506
         }
473
-        block.insts.retain(|inst| !replacements.contains_key(&inst.id));
507
+        block
508
+            .insts
509
+            .retain(|inst| !replacements.contains_key(&inst.id));
474510
         if let Some(ref mut term) = block.terminator {
475511
             remap_terminator_operands(term, &replacements);
476512
         }
@@ -490,12 +526,23 @@ fn remap_terminator_operands(term: &mut Terminator, map: &HashMap<ValueId, Value
490526
     match term {
491527
         Terminator::Return(Some(v)) => *v = r(v),
492528
         Terminator::Branch(_, args) => {
493
-            for a in args.iter_mut() { *a = r(a); }
529
+            for a in args.iter_mut() {
530
+                *a = r(a);
531
+            }
494532
         }
495
-        Terminator::CondBranch { cond, true_args, false_args, .. } => {
533
+        Terminator::CondBranch {
534
+            cond,
535
+            true_args,
536
+            false_args,
537
+            ..
538
+        } => {
496539
             *cond = r(cond);
497
-            for a in true_args.iter_mut() { *a = r(a); }
498
-            for a in false_args.iter_mut() { *a = r(a); }
540
+            for a in true_args.iter_mut() {
541
+                *a = r(a);
542
+            }
543
+            for a in false_args.iter_mut() {
544
+                *a = r(a);
545
+            }
499546
         }
500547
         Terminator::Switch { selector, .. } => {
501548
             *selector = r(selector);
@@ -507,36 +554,45 @@ fn remap_terminator_operands(term: &mut Terminator, map: &HashMap<ValueId, Value
507554
 #[cfg(test)]
508555
 mod tests {
509556
     use super::*;
510
-    use std::fs;
511
-    use std::path::PathBuf;
512
-    use crate::ir::types::{IrType, IntWidth};
557
+    use crate::ir::lower;
558
+    use crate::ir::types::{IntWidth, IrType};
559
+    use crate::lexer::{tokenize, SourceForm};
560
+    use crate::lexer::{Position, Span};
513561
     use crate::opt::pass::Pass;
514562
     use crate::opt::pass::PassManager;
563
+    use crate::opt::pipeline::OptLevel;
515564
     use crate::opt::{
516565
         bce::Bce, call_resolve::CallResolve, const_fold::ConstFold, const_prop::ConstProp,
517
-        dead_func::DeadFuncElim, dse::Dse, fusion::LoopFusion, global_lsf::GlobalLsf,
518
-        interchange::LoopInterchange, inline::Inline, licm::Licm, lsf::LocalLsf,
519
-        mem2reg::Mem2Reg, peel::LoopPeel, preheader::PreheaderInsert, simplify_cfg::SimplifyCfg,
520
-        sroa::Sroa, strength_reduce::StrengthReduce, unroll::LoopUnroll, unswitch::LoopUnswitch,
521
-        fission::LoopFission,
566
+        dead_func::DeadFuncElim, dse::Dse, fission::LoopFission, fusion::LoopFusion,
567
+        global_lsf::GlobalLsf, inline::Inline, interchange::LoopInterchange, licm::Licm,
568
+        lsf::LocalLsf, mem2reg::Mem2Reg, peel::LoopPeel, preheader::PreheaderInsert,
569
+        simplify_cfg::SimplifyCfg, sroa::Sroa, strength_reduce::StrengthReduce, unroll::LoopUnroll,
570
+        unswitch::LoopUnswitch,
522571
     };
523
-    use crate::opt::pipeline::OptLevel;
524
-    use crate::lexer::{Position, Span};
525
-    use crate::lexer::{SourceForm, tokenize};
526572
     use crate::parser::Parser;
527573
     use crate::preprocess::PreprocConfig;
528574
     use crate::sema::{resolve, validate};
529
-    use crate::ir::lower;
575
+    use std::fs;
576
+    use std::path::PathBuf;
530577
 
531578
     fn span() -> Span {
532579
         let pos = Position { line: 0, col: 0 };
533
-        Span { file_id: 0, start: pos, end: pos }
580
+        Span {
581
+            file_id: 0,
582
+            start: pos,
583
+            end: pos,
584
+        }
534585
     }
535586
 
536587
     fn push_inst(func: &mut Function, block: BlockId, kind: InstKind, ty: IrType) -> ValueId {
537588
         let id = func.next_value_id();
538589
         func.register_type(id, ty.clone());
539
-        func.block_mut(block).insts.push(Inst { id, kind, ty, span: span() });
590
+        func.block_mut(block).insts.push(Inst {
591
+            id,
592
+            kind,
593
+            ty,
594
+            span: span(),
595
+        });
540596
         id
541597
     }
542598
 
@@ -555,14 +611,26 @@ mod tests {
555611
         let tokens = tokenize(&pp.text, 0, SourceForm::FreeForm).expect("tokenize fixture");
556612
         let mut parser = Parser::new(&tokens);
557613
         let units = parser.parse_file().expect("parse fixture");
558
-        let (st, type_layouts) = { let rr = resolve::resolve_file(&units, &[]).expect("resolve fixture"); (rr.st, rr.type_layouts) };
614
+        let (st, type_layouts) = {
615
+            let rr = resolve::resolve_file(&units, &[]).expect("resolve fixture");
616
+            (rr.st, rr.type_layouts)
617
+        };
559618
         let diags = validate::validate_file(&units, &st);
560619
         assert!(
561
-            !diags.iter().any(|diag| diag.kind == validate::DiagKind::Error),
620
+            !diags
621
+                .iter()
622
+                .any(|diag| diag.kind == validate::DiagKind::Error),
562623
             "fixture should lower cleanly: {:?}",
563624
             diags
564625
         );
565
-        lower::lower_file(&units, &st, &type_layouts, std::collections::HashMap::new(), std::collections::HashMap::new()).0
626
+        lower::lower_file(
627
+            &units,
628
+            &st,
629
+            &type_layouts,
630
+            std::collections::HashMap::new(),
631
+            std::collections::HashMap::new(),
632
+        )
633
+        .0
566634
     }
567635
 
568636
     fn build_pre_gvn_o2_pipeline() -> PassManager {
@@ -758,9 +826,16 @@ mod tests {
758826
             .iter()
759827
             .filter(|inst| matches!(inst.kind, InstKind::Call(..)))
760828
             .count();
761
-        assert_eq!(call_count, 1, "PURE call should reuse equivalent dominating args");
829
+        assert_eq!(
830
+            call_count, 1,
831
+            "PURE call should reuse equivalent dominating args"
832
+        );
762833
 
763
-        match caller.blocks[0].terminator.as_ref().expect("return terminator") {
834
+        match caller.blocks[0]
835
+            .terminator
836
+            .as_ref()
837
+            .expect("return terminator")
838
+        {
764839
             Terminator::Return(Some(v)) => assert_eq!(*v, call1),
765840
             other => panic!("unexpected terminator: {:?}", other),
766841
         }
@@ -774,7 +849,8 @@ mod tests {
774849
             id: ValueId(0),
775850
             fortran_noalias: false,
776851
         };
777
-        let mut callee = Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
852
+        let mut callee =
853
+            Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
778854
         callee.is_pure = true;
779855
         let entry = callee.entry;
780856
 
@@ -784,7 +860,12 @@ mod tests {
784860
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
785861
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
786862
         );
787
-        push_inst(&mut callee, entry, InstKind::Store(ValueId(0), slot), IrType::Void);
863
+        push_inst(
864
+            &mut callee,
865
+            entry,
866
+            InstKind::Store(ValueId(0), slot),
867
+            IrType::Void,
868
+        );
788869
         let arg_ptr = push_inst(
789870
             &mut callee,
790871
             entry,
@@ -814,7 +895,8 @@ mod tests {
814895
             id: ValueId(0),
815896
             fortran_noalias: false,
816897
         };
817
-        let mut callee = Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
898
+        let mut callee =
899
+            Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
818900
         callee.is_pure = true;
819901
         let callee_entry = callee.entry;
820902
         let slot = push_inst(
@@ -823,7 +905,12 @@ mod tests {
823905
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
824906
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
825907
         );
826
-        push_inst(&mut callee, callee_entry, InstKind::Store(ValueId(0), slot), IrType::Void);
908
+        push_inst(
909
+            &mut callee,
910
+            callee_entry,
911
+            InstKind::Store(ValueId(0), slot),
912
+            IrType::Void,
913
+        );
827914
         let arg_ptr = push_inst(
828915
             &mut callee,
829916
             callee_entry,
@@ -855,7 +942,12 @@ mod tests {
855942
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
856943
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
857944
         );
858
-        push_inst(&mut caller, entry, InstKind::Store(c, wrapper), IrType::Void);
945
+        push_inst(
946
+            &mut caller,
947
+            entry,
948
+            InstKind::Store(c, wrapper),
949
+            IrType::Void,
950
+        );
859951
         let call = push_inst(
860952
             &mut caller,
861953
             entry,
@@ -878,7 +970,8 @@ mod tests {
878970
             id: ValueId(0),
879971
             fortran_noalias: false,
880972
         };
881
-        let mut callee = Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
973
+        let mut callee =
974
+            Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
882975
         callee.is_pure = true;
883976
         let callee_entry = callee.entry;
884977
         let shadow = push_inst(
@@ -887,7 +980,12 @@ mod tests {
887980
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
888981
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
889982
         );
890
-        push_inst(&mut callee, callee_entry, InstKind::Store(ValueId(0), shadow), IrType::Void);
983
+        push_inst(
984
+            &mut callee,
985
+            callee_entry,
986
+            InstKind::Store(ValueId(0), shadow),
987
+            IrType::Void,
988
+        );
891989
         let arg_ptr = push_inst(
892990
             &mut callee,
893991
             callee_entry,
@@ -942,7 +1040,12 @@ mod tests {
9421040
             InstKind::Call(FuncRef::Internal(0), vec![wrap1]),
9431041
             IrType::Int(IntWidth::I32),
9441042
         );
945
-        push_inst(&mut caller, entry, InstKind::Store(call1, first), IrType::Void);
1043
+        push_inst(
1044
+            &mut caller,
1045
+            entry,
1046
+            InstKind::Store(call1, first),
1047
+            IrType::Void,
1048
+        );
9461049
         let c3 = push_inst(
9471050
             &mut caller,
9481051
             entry,
@@ -968,9 +1071,24 @@ mod tests {
9681071
             InstKind::Call(FuncRef::Internal(0), vec![wrap2]),
9691072
             IrType::Int(IntWidth::I32),
9701073
         );
971
-        push_inst(&mut caller, entry, InstKind::Store(call2, second), IrType::Void);
972
-        let left = push_inst(&mut caller, entry, InstKind::Load(first), IrType::Int(IntWidth::I32));
973
-        let right = push_inst(&mut caller, entry, InstKind::Load(second), IrType::Int(IntWidth::I32));
1074
+        push_inst(
1075
+            &mut caller,
1076
+            entry,
1077
+            InstKind::Store(call2, second),
1078
+            IrType::Void,
1079
+        );
1080
+        let left = push_inst(
1081
+            &mut caller,
1082
+            entry,
1083
+            InstKind::Load(first),
1084
+            IrType::Int(IntWidth::I32),
1085
+        );
1086
+        let right = push_inst(
1087
+            &mut caller,
1088
+            entry,
1089
+            InstKind::Load(second),
1090
+            IrType::Int(IntWidth::I32),
1091
+        );
9741092
         let sum = push_inst(
9751093
             &mut caller,
9761094
             entry,
@@ -980,9 +1098,16 @@ mod tests {
9801098
         caller.block_mut(entry).terminator = Some(Terminator::Return(Some(sum)));
9811099
         m.add_function(caller);
9821100
 
983
-        let pure_calls: Vec<PureCallPolicy> = m.functions.iter().map(PureCallPolicy::for_function).collect();
1101
+        let pure_calls: Vec<PureCallPolicy> = m
1102
+            .functions
1103
+            .iter()
1104
+            .map(PureCallPolicy::for_function)
1105
+            .collect();
9841106
         assert!(pure_calls[0].reusable);
985
-        assert_eq!(pure_calls[0].arg_policies, vec![PureArgPolicy::ReadOnlyWrapperPtr]);
1107
+        assert_eq!(
1108
+            pure_calls[0].arg_policies,
1109
+            vec![PureArgPolicy::ReadOnlyWrapperPtr]
1110
+        );
9861111
         let wrappers = wrapper_alloca_values(&m.functions[1], &pure_calls);
9871112
         assert_eq!(wrappers.get(&wrap1), Some(&c2));
9881113
         assert_eq!(wrappers.get(&wrap2), Some(&c4));
@@ -1002,9 +1127,14 @@ mod tests {
10021127
             .iter()
10031128
             .find(|inst| inst.id == call2)
10041129
             .expect("call2 inst");
1005
-        let key1 = key_of(call1_inst, &replacements, &pure_calls, &wrappers).expect("call1 should key");
1006
-        let key2 = key_of(call2_inst, &replacements, &pure_calls, &wrappers).expect("call2 should key");
1007
-        assert_eq!(key1, key2, "wrapper-based call keys should line up before the pass runs");
1130
+        let key1 =
1131
+            key_of(call1_inst, &replacements, &pure_calls, &wrappers).expect("call1 should key");
1132
+        let key2 =
1133
+            key_of(call2_inst, &replacements, &pure_calls, &wrappers).expect("call2 should key");
1134
+        assert_eq!(
1135
+            key1, key2,
1136
+            "wrapper-based call keys should line up before the pass runs"
1137
+        );
10081138
 
10091139
         let pass = Gvn;
10101140
         assert!(pass.run(&mut m));
@@ -1028,7 +1158,8 @@ mod tests {
10281158
             id: ValueId(0),
10291159
             fortran_noalias: false,
10301160
         };
1031
-        let mut callee = Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
1161
+        let mut callee =
1162
+            Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
10321163
         callee.is_pure = true;
10331164
         let entry = callee.entry;
10341165
         let if_end = callee.create_block("if_end");
@@ -1041,7 +1172,12 @@ mod tests {
10411172
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
10421173
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
10431174
         );
1044
-        push_inst(&mut callee, entry, InstKind::Store(ValueId(0), shadow), IrType::Void);
1175
+        push_inst(
1176
+            &mut callee,
1177
+            entry,
1178
+            InstKind::Store(ValueId(0), shadow),
1179
+            IrType::Void,
1180
+        );
10451181
         let result = push_inst(
10461182
             &mut callee,
10471183
             entry,
@@ -1054,7 +1190,12 @@ mod tests {
10541190
             InstKind::Load(shadow),
10551191
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
10561192
         );
1057
-        let n1 = push_inst(&mut callee, entry, InstKind::Load(p1), IrType::Int(IntWidth::I32));
1193
+        let n1 = push_inst(
1194
+            &mut callee,
1195
+            entry,
1196
+            InstKind::Load(p1),
1197
+            IrType::Int(IntWidth::I32),
1198
+        );
10581199
         let one = push_inst(
10591200
             &mut callee,
10601201
             entry,
@@ -1081,7 +1222,12 @@ mod tests {
10811222
             InstKind::ConstInt(1, IntWidth::I32),
10821223
             IrType::Int(IntWidth::I32),
10831224
         );
1084
-        push_inst(&mut callee, if_then, InstKind::Store(then_one, result), IrType::Void);
1225
+        push_inst(
1226
+            &mut callee,
1227
+            if_then,
1228
+            InstKind::Store(then_one, result),
1229
+            IrType::Void,
1230
+        );
10851231
         callee.block_mut(if_then).terminator = Some(Terminator::Branch(if_end, vec![]));
10861232
 
10871233
         let p2 = push_inst(
@@ -1090,14 +1236,24 @@ mod tests {
10901236
             InstKind::Load(shadow),
10911237
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
10921238
         );
1093
-        let n2 = push_inst(&mut callee, if_else, InstKind::Load(p2), IrType::Int(IntWidth::I32));
1239
+        let n2 = push_inst(
1240
+            &mut callee,
1241
+            if_else,
1242
+            InstKind::Load(p2),
1243
+            IrType::Int(IntWidth::I32),
1244
+        );
10941245
         let p3 = push_inst(
10951246
             &mut callee,
10961247
             if_else,
10971248
             InstKind::Load(shadow),
10981249
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
10991250
         );
1100
-        let n3 = push_inst(&mut callee, if_else, InstKind::Load(p3), IrType::Int(IntWidth::I32));
1251
+        let n3 = push_inst(
1252
+            &mut callee,
1253
+            if_else,
1254
+            InstKind::Load(p3),
1255
+            IrType::Int(IntWidth::I32),
1256
+        );
11011257
         let one2 = push_inst(
11021258
             &mut callee,
11031259
             if_else,
@@ -1116,7 +1272,12 @@ mod tests {
11161272
             InstKind::Load(shadow),
11171273
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11181274
         );
1119
-        let n4 = push_inst(&mut callee, if_else, InstKind::Load(p4), IrType::Int(IntWidth::I32));
1275
+        let n4 = push_inst(
1276
+            &mut callee,
1277
+            if_else,
1278
+            InstKind::Load(p4),
1279
+            IrType::Int(IntWidth::I32),
1280
+        );
11201281
         let one3 = push_inst(
11211282
             &mut callee,
11221283
             if_else,
@@ -1135,7 +1296,12 @@ mod tests {
11351296
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
11361297
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11371298
         );
1138
-        push_inst(&mut callee, if_else, InstKind::Store(dec2, wrap), IrType::Void);
1299
+        push_inst(
1300
+            &mut callee,
1301
+            if_else,
1302
+            InstKind::Store(dec2, wrap),
1303
+            IrType::Void,
1304
+        );
11391305
         let rec = push_inst(
11401306
             &mut callee,
11411307
             if_else,
@@ -1148,10 +1314,20 @@ mod tests {
11481314
             InstKind::IMul(n2, rec),
11491315
             IrType::Int(IntWidth::I32),
11501316
         );
1151
-        push_inst(&mut callee, if_else, InstKind::Store(prod, result), IrType::Void);
1317
+        push_inst(
1318
+            &mut callee,
1319
+            if_else,
1320
+            InstKind::Store(prod, result),
1321
+            IrType::Void,
1322
+        );
11521323
         callee.block_mut(if_else).terminator = Some(Terminator::Branch(if_end, vec![]));
11531324
 
1154
-        let final_val = push_inst(&mut callee, if_end, InstKind::Load(result), IrType::Int(IntWidth::I32));
1325
+        let final_val = push_inst(
1326
+            &mut callee,
1327
+            if_end,
1328
+            InstKind::Load(result),
1329
+            IrType::Int(IntWidth::I32),
1330
+        );
11551331
         callee.block_mut(if_end).terminator = Some(Terminator::Return(Some(final_val)));
11561332
         m.add_function(callee);
11571333
 
@@ -1175,7 +1351,12 @@ mod tests {
11751351
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
11761352
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11771353
         );
1178
-        push_inst(&mut caller, caller_entry, InstKind::Store(unit2, wrap1), IrType::Void);
1354
+        push_inst(
1355
+            &mut caller,
1356
+            caller_entry,
1357
+            InstKind::Store(unit2, wrap1),
1358
+            IrType::Void,
1359
+        );
11791360
         let call1 = push_inst(
11801361
             &mut caller,
11811362
             caller_entry,
@@ -1188,7 +1369,12 @@ mod tests {
11881369
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
11891370
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11901371
         );
1191
-        push_inst(&mut caller, caller_entry, InstKind::Store(unit, wrap2), IrType::Void);
1372
+        push_inst(
1373
+            &mut caller,
1374
+            caller_entry,
1375
+            InstKind::Store(unit, wrap2),
1376
+            IrType::Void,
1377
+        );
11921378
         let call2 = push_inst(
11931379
             &mut caller,
11941380
             caller_entry,
@@ -1212,7 +1398,10 @@ mod tests {
12121398
             .iter()
12131399
             .filter(|inst| matches!(inst.kind, InstKind::Call(..)))
12141400
             .count();
1215
-        assert_eq!(call_count, 1, "recursive PURE factorial calls should dedupe");
1401
+        assert_eq!(
1402
+            call_count, 1,
1403
+            "recursive PURE factorial calls should dedupe"
1404
+        );
12161405
     }
12171406
 
12181407
     #[test]
@@ -1274,7 +1463,8 @@ mod tests {
12741463
             id: ValueId(0),
12751464
             fortran_noalias: false,
12761465
         };
1277
-        let mut callee = Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
1466
+        let mut callee =
1467
+            Function::new("heavy_fact".into(), vec![param], IrType::Int(IntWidth::I32));
12781468
         callee.is_pure = true;
12791469
         let callee_entry = callee.entry;
12801470
         let shadow = push_inst(
@@ -1283,7 +1473,12 @@ mod tests {
12831473
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
12841474
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
12851475
         );
1286
-        push_inst(&mut callee, callee_entry, InstKind::Store(ValueId(0), shadow), IrType::Void);
1476
+        push_inst(
1477
+            &mut callee,
1478
+            callee_entry,
1479
+            InstKind::Store(ValueId(0), shadow),
1480
+            IrType::Void,
1481
+        );
12871482
         let arg_ptr = push_inst(
12881483
             &mut callee,
12891484
             callee_entry,
@@ -1307,7 +1502,10 @@ mod tests {
13071502
             .iter()
13081503
             .filter(|inst| matches!(inst.kind, InstKind::Call(..)))
13091504
             .count();
1310
-        assert_eq!(call_count, 1, "caller-before-callee ordering should still dedupe");
1505
+        assert_eq!(
1506
+            call_count, 1,
1507
+            "caller-before-callee ordering should still dedupe"
1508
+        );
13111509
     }
13121510
 
13131511
     #[test]
@@ -1316,7 +1514,11 @@ mod tests {
13161514
         let pm = build_pre_gvn_o2_pipeline();
13171515
         pm.run(&mut module);
13181516
 
1319
-        let pure_calls: Vec<PureCallPolicy> = module.functions.iter().map(PureCallPolicy::for_function).collect();
1517
+        let pure_calls: Vec<PureCallPolicy> = module
1518
+            .functions
1519
+            .iter()
1520
+            .map(PureCallPolicy::for_function)
1521
+            .collect();
13201522
         assert!(
13211523
             pure_calls.iter().any(|policy| policy.reusable),
13221524
             "at least one function in the fixture should remain a reusable PURE callee:\n{}",
@@ -1335,7 +1537,10 @@ mod tests {
13351537
         );
13361538
 
13371539
         let pass = Gvn;
1338
-        assert!(pass.run(&mut module), "GVN should make progress on the real fixture");
1540
+        assert!(
1541
+            pass.run(&mut module),
1542
+            "GVN should make progress on the real fixture"
1543
+        );
13391544
 
13401545
         let caller = &module.functions[caller_idx];
13411546
         let call_count = caller.blocks[0]
@@ -1343,7 +1548,10 @@ mod tests {
13431548
             .iter()
13441549
             .filter(|inst| matches!(inst.kind, InstKind::Call(FuncRef::Internal(_), _)))
13451550
             .count();
1346
-        assert_eq!(call_count, 1, "real fixture caller should end with one PURE recursive call");
1551
+        assert_eq!(
1552
+            call_count, 1,
1553
+            "real fixture caller should end with one PURE recursive call"
1554
+        );
13471555
     }
13481556
 
13491557
     #[test]
@@ -1398,7 +1606,10 @@ mod tests {
13981606
         m.add_function(caller);
13991607
 
14001608
         let pass = Gvn;
1401
-        assert!(!pass.run(&mut m), "pointer-arg PURE calls must stay distinct");
1609
+        assert!(
1610
+            !pass.run(&mut m),
1611
+            "pointer-arg PURE calls must stay distinct"
1612
+        );
14021613
 
14031614
         let caller = &m.functions[1];
14041615
         let call_count = caller.blocks[0]
src/opt/inline.rsmodified
350 lines changed — click to load
@@ -13,14 +13,14 @@
1313
 //!   5. Split the call-containing block: pre-call instructions +
1414
 //!      branch to cloned entry, post-call block receives return value
1515
 
16
-use std::collections::HashMap;
17
-use crate::ir::inst::*;
18
-use crate::ir::types::IrType;
19
-use crate::ir::walk::prune_unreachable;
2016
 use super::callgraph::CallGraph;
2117
 use super::loop_utils::{remap_inst_kind, remap_terminator};
2218
 use super::pass::Pass;
2319
 use super::pipeline::OptLevel;
20
+use crate::ir::inst::*;
21
+use crate::ir::types::IrType;
22
+use crate::ir::walk::prune_unreachable;
23
+use std::collections::HashMap;
2424
 
2525
 /// Maximum callee instruction count for inlining.
2626
 const INLINE_THRESHOLD_O1: usize = 20;
@@ -43,10 +43,14 @@ impl Inline {
4343
 }
4444
 
4545
 impl Pass for Inline {
46
-    fn name(&self) -> &'static str { "inline" }
46
+    fn name(&self) -> &'static str {
47
+        "inline"
48
+    }
4749
 
4850
     fn run(&self, module: &mut Module) -> bool {
49
-        if self.threshold == 0 { return false; }
51
+        if self.threshold == 0 {
52
+            return false;
53
+        }
5054
 
5155
         let cg = CallGraph::build(module);
5256
         let order = cg.bottom_up_order();
@@ -77,11 +81,17 @@ fn inline_calls_in_function(
7781
                 if let InstKind::Call(FuncRef::Internal(callee_idx), args) = &inst.kind {
7882
                     let ci = *callee_idx;
7983
                     // Don't inline recursive functions.
80
-                    if cg.is_recursive(ci) { continue; }
84
+                    if cg.is_recursive(ci) {
85
+                        continue;
86
+                    }
8187
                     // Don't self-inline.
82
-                    if ci == caller_idx { continue; }
88
+                    if ci == caller_idx {
89
+                        continue;
90
+                    }
8391
                     // Cost check.
84
-                    if cg.inline_cost(ci) > threshold { continue; }
92
+                    if cg.inline_cost(ci) > threshold {
93
+                        continue;
94
+                    }
8595
                     // Argument/parameter type agreement.  When a
8696
                     // Fortran OPTIONAL parameter is absent at a call
8797
                     // site, the caller passes `const_i64 0` as a null
@@ -94,14 +104,19 @@ fn inline_calls_in_function(
94104
                     // callee param type exactly.  The same check also
95105
                     // guards any future call-boundary coercion shims.
96106
                     let callee = &module.functions[ci as usize];
97
-                    if callee.params.len() != args.len() { continue; }
98
-                    let mismatched = callee.params.iter().zip(args.iter()).any(|(p, a)| {
99
-                        match caller.value_type(*a) {
100
-                            Some(ty) => ty != p.ty,
101
-                            None => true,
102
-                        }
103
-                    });
104
-                    if mismatched { continue; }
107
+                    if callee.params.len() != args.len() {
108
+                        continue;
109
+                    }
110
+                    let mismatched =
111
+                        callee.params.iter().zip(args.iter()).any(|(p, a)| {
112
+                            match caller.value_type(*a) {
113
+                                Some(ty) => ty != p.ty,
114
+                                None => true,
115
+                            }
116
+                        });
117
+                    if mismatched {
118
+                        continue;
119
+                    }
105120
                     sites.push((block.id, inst_idx, ci, args.clone()));
106121
                 }
107122
             }
@@ -109,7 +124,9 @@ fn inline_calls_in_function(
109124
         sites
110125
     };
111126
 
112
-    if call_sites.is_empty() { return false; }
127
+    if call_sites.is_empty() {
128
+        return false;
129
+    }
113130
 
114131
     // Inline one call site, then return true to let the pass manager
115132
     // re-run us. Processing multiple sites in one invocation is unsafe:
@@ -117,139 +134,133 @@ fn inline_calls_in_function(
117134
     // same block. The pass manager's fixpoint loop handles re-invocation.
118135
     let (call_block_id, call_inst_idx, callee_idx, caller_args) = call_sites[0].clone();
119136
     {
137
+        // Clone the callee's body into the caller.
138
+        let callee = &module.functions[callee_idx as usize];
139
+        let callee_entry = callee.entry;
140
+        let callee_blocks: Vec<BasicBlock> = callee.blocks.clone();
141
+        let callee_params: Vec<Param> = callee.params.clone();
142
+        let callee_return_ty = callee.return_type.clone();
143
+
144
+        let caller = &mut module.functions[caller_idx as usize];
145
+
146
+        // Build value map: callee params → caller args.
147
+        let mut val_map: HashMap<ValueId, ValueId> = HashMap::new();
148
+        for (param, &arg) in callee_params.iter().zip(caller_args.iter()) {
149
+            val_map.insert(param.id, arg);
150
+        }
120151
 
121
-    // Clone the callee's body into the caller.
122
-    let callee = &module.functions[callee_idx as usize];
123
-    let callee_entry = callee.entry;
124
-    let callee_blocks: Vec<BasicBlock> = callee.blocks.clone();
125
-    let callee_params: Vec<Param> = callee.params.clone();
126
-    let callee_return_ty = callee.return_type.clone();
127
-
128
-    let caller = &mut module.functions[caller_idx as usize];
129
-
130
-    // Build value map: callee params → caller args.
131
-    let mut val_map: HashMap<ValueId, ValueId> = HashMap::new();
132
-    for (param, &arg) in callee_params.iter().zip(caller_args.iter()) {
133
-        val_map.insert(param.id, arg);
134
-    }
135
-
136
-    // Allocate fresh IDs for all callee values.
137
-    let mut block_map: HashMap<BlockId, BlockId> = HashMap::new();
138
-    for cb in &callee_blocks {
139
-        let new_bid = caller.create_block(&format!("inline_{}", cb.name));
140
-        block_map.insert(cb.id, new_bid);
141
-    }
142
-
143
-    // Create post-call block to receive the return value.
144
-    let post_call = caller.create_block("inline_post");
145
-    let has_return_val = !matches!(callee_return_ty, IrType::Void);
152
+        // Allocate fresh IDs for all callee values.
153
+        let mut block_map: HashMap<BlockId, BlockId> = HashMap::new();
154
+        for cb in &callee_blocks {
155
+            let new_bid = caller.create_block(&format!("inline_{}", cb.name));
156
+            block_map.insert(cb.id, new_bid);
157
+        }
146158
 
147
-    let result_param_id = if has_return_val {
148
-        let pid = caller.next_value_id();
149
-        caller.register_type(pid, callee_return_ty.clone());
150
-        caller.block_mut(post_call).params.push(BlockParam {
151
-            id: pid,
152
-            ty: callee_return_ty.clone(),
153
-        });
154
-        Some(pid)
155
-    } else {
156
-        None
157
-    };
159
+        // Create post-call block to receive the return value.
160
+        let post_call = caller.create_block("inline_post");
161
+        let has_return_val = !matches!(callee_return_ty, IrType::Void);
158162
 
159
-    // Clone block params and instructions.
160
-    for cb in &callee_blocks {
161
-        let new_bid = block_map[&cb.id];
162
-        // Clone block params.
163
-        for bp in &cb.params {
164
-            let new_id = caller.next_value_id();
165
-            caller.register_type(new_id, bp.ty.clone());
166
-            val_map.insert(bp.id, new_id);
167
-            caller.block_mut(new_bid).params.push(BlockParam {
168
-                id: new_id,
169
-                ty: bp.ty.clone(),
170
-            });
171
-        }
172
-        // Clone instructions.
173
-        for inst in &cb.insts {
174
-            let new_id = caller.next_value_id();
175
-            caller.register_type(new_id, inst.ty.clone());
176
-            val_map.insert(inst.id, new_id);
177
-            let new_kind = remap_inst_kind(&inst.kind, &val_map);
178
-            caller.block_mut(new_bid).insts.push(Inst {
179
-                id: new_id,
180
-                kind: new_kind,
181
-                ty: inst.ty.clone(),
182
-                span: inst.span,
163
+        let result_param_id = if has_return_val {
164
+            let pid = caller.next_value_id();
165
+            caller.register_type(pid, callee_return_ty.clone());
166
+            caller.block_mut(post_call).params.push(BlockParam {
167
+                id: pid,
168
+                ty: callee_return_ty.clone(),
183169
             });
184
-        }
185
-    }
170
+            Some(pid)
171
+        } else {
172
+            None
173
+        };
186174
 
187
-    // Clone terminators, replacing Return with Branch to post_call.
188
-    for cb in &callee_blocks {
189
-        let new_bid = block_map[&cb.id];
190
-        let new_term = match &cb.terminator {
191
-            Some(Terminator::Return(Some(val))) => {
192
-                let remapped = *val_map.get(val).unwrap_or(val);
193
-                Terminator::Branch(post_call, vec![remapped])
194
-            }
195
-            Some(Terminator::Return(None)) => {
196
-                Terminator::Branch(post_call, vec![])
175
+        // Clone block params and instructions.
176
+        for cb in &callee_blocks {
177
+            let new_bid = block_map[&cb.id];
178
+            // Clone block params.
179
+            for bp in &cb.params {
180
+                let new_id = caller.next_value_id();
181
+                caller.register_type(new_id, bp.ty.clone());
182
+                val_map.insert(bp.id, new_id);
183
+                caller.block_mut(new_bid).params.push(BlockParam {
184
+                    id: new_id,
185
+                    ty: bp.ty.clone(),
186
+                });
197187
             }
198
-            Some(other) => {
199
-                remap_terminator(other, &block_map, &val_map)
188
+            // Clone instructions.
189
+            for inst in &cb.insts {
190
+                let new_id = caller.next_value_id();
191
+                caller.register_type(new_id, inst.ty.clone());
192
+                val_map.insert(inst.id, new_id);
193
+                let new_kind = remap_inst_kind(&inst.kind, &val_map);
194
+                caller.block_mut(new_bid).insts.push(Inst {
195
+                    id: new_id,
196
+                    kind: new_kind,
197
+                    ty: inst.ty.clone(),
198
+                    span: inst.span,
199
+                });
200200
             }
201
-            None => Terminator::Unreachable,
202
-        };
203
-        caller.block_mut(new_bid).terminator = Some(new_term);
204
-    }
201
+        }
205202
 
206
-    // Split the call-containing block: move instructions after the call
207
-    // into the post-call block.
208
-    let call_block = caller.block_mut(call_block_id);
209
-    let call_result_id = call_block.insts[call_inst_idx].id;
203
+        // Clone terminators, replacing Return with Branch to post_call.
204
+        for cb in &callee_blocks {
205
+            let new_bid = block_map[&cb.id];
206
+            let new_term = match &cb.terminator {
207
+                Some(Terminator::Return(Some(val))) => {
208
+                    let remapped = *val_map.get(val).unwrap_or(val);
209
+                    Terminator::Branch(post_call, vec![remapped])
210
+                }
211
+                Some(Terminator::Return(None)) => Terminator::Branch(post_call, vec![]),
212
+                Some(other) => remap_terminator(other, &block_map, &val_map),
213
+                None => Terminator::Unreachable,
214
+            };
215
+            caller.block_mut(new_bid).terminator = Some(new_term);
216
+        }
210217
 
211
-    // Move post-call instructions to the new block.
212
-    let post_insts: Vec<Inst> = call_block.insts.split_off(call_inst_idx + 1);
213
-    let old_term = call_block.terminator.take();
218
+        // Split the call-containing block: move instructions after the call
219
+        // into the post-call block.
220
+        let call_block = caller.block_mut(call_block_id);
221
+        let call_result_id = call_block.insts[call_inst_idx].id;
214222
 
215
-    // Remove the call instruction itself.
216
-    call_block.insts.pop(); // removes the call at call_inst_idx
223
+        // Move post-call instructions to the new block.
224
+        let post_insts: Vec<Inst> = call_block.insts.split_off(call_inst_idx + 1);
225
+        let old_term = call_block.terminator.take();
217226
 
218
-    // Add branch from call block to inlined entry.
219
-    let inlined_entry = block_map[&callee_entry];
220
-    caller.block_mut(call_block_id).terminator =
221
-        Some(Terminator::Branch(inlined_entry, vec![]));
227
+        // Remove the call instruction itself.
228
+        call_block.insts.pop(); // removes the call at call_inst_idx
222229
 
223
-    // Populate post-call block with remaining instructions and terminator.
224
-    // Remap uses of the call result to the post-call block param.
225
-    let mut post_remap: HashMap<ValueId, ValueId> = HashMap::new();
226
-    if let Some(param_id) = result_param_id {
227
-        post_remap.insert(call_result_id, param_id);
228
-    }
230
+        // Add branch from call block to inlined entry.
231
+        let inlined_entry = block_map[&callee_entry];
232
+        caller.block_mut(call_block_id).terminator =
233
+            Some(Terminator::Branch(inlined_entry, vec![]));
229234
 
230
-    for inst in post_insts {
231
-        let new_kind = if post_remap.is_empty() {
232
-            inst.kind.clone()
233
-        } else {
234
-            remap_inst_kind(&inst.kind, &post_remap)
235
-        };
236
-        caller.block_mut(post_call).insts.push(Inst {
237
-            id: inst.id,
238
-            kind: new_kind,
239
-            ty: inst.ty,
240
-            span: inst.span,
241
-        });
242
-    }
235
+        // Populate post-call block with remaining instructions and terminator.
236
+        // Remap uses of the call result to the post-call block param.
237
+        let mut post_remap: HashMap<ValueId, ValueId> = HashMap::new();
238
+        if let Some(param_id) = result_param_id {
239
+            post_remap.insert(call_result_id, param_id);
240
+        }
243241
 
244
-    if let Some(term) = old_term {
245
-        let new_term = if post_remap.is_empty() {
246
-            term
247
-        } else {
248
-            remap_terminator(&term, &HashMap::new(), &post_remap)
249
-        };
250
-        caller.block_mut(post_call).terminator = Some(new_term);
251
-    }
242
+        for inst in post_insts {
243
+            let new_kind = if post_remap.is_empty() {
244
+                inst.kind.clone()
245
+            } else {
246
+                remap_inst_kind(&inst.kind, &post_remap)
247
+            };
248
+            caller.block_mut(post_call).insts.push(Inst {
249
+                id: inst.id,
250
+                kind: new_kind,
251
+                ty: inst.ty,
252
+                span: inst.span,
253
+            });
254
+        }
252255
 
256
+        if let Some(term) = old_term {
257
+            let new_term = if post_remap.is_empty() {
258
+                term
259
+            } else {
260
+                remap_terminator(&term, &HashMap::new(), &post_remap)
261
+            };
262
+            caller.block_mut(post_call).terminator = Some(new_term);
263
+        }
253264
     } // end single inline
254265
 
255266
     let caller = &mut module.functions[caller_idx as usize];
@@ -260,7 +271,7 @@ fn inline_calls_in_function(
260271
 #[cfg(test)]
261272
 mod tests {
262273
     use super::*;
263
-    use crate::ir::types::{IrType, IntWidth};
274
+    use crate::ir::types::{IntWidth, IrType};
264275
     use crate::opt::pass::Pass;
265276
 
266277
     #[test]
src/opt/interchange.rsmodified
321 lines changed — click to load
@@ -24,20 +24,24 @@
2424
 //! use both IVs as simple direct subscripts with no cross-iteration
2525
 //! read-before-write. This avoids needing full dependence analysis.
2626
 
27
-use crate::ir::inst::*;
28
-use crate::ir::walk::predecessors;
2927
 use super::loop_tree::build_loop_tree;
3028
 use super::pass::Pass;
29
+use crate::ir::inst::*;
30
+use crate::ir::walk::predecessors;
3131
 
3232
 pub struct LoopInterchange;
3333
 
3434
 impl Pass for LoopInterchange {
35
-    fn name(&self) -> &'static str { "loop-interchange" }
35
+    fn name(&self) -> &'static str {
36
+        "loop-interchange"
37
+    }
3638
 
3739
     fn run(&self, module: &mut Module) -> bool {
3840
         let mut changed = false;
3941
         for func in &mut module.functions {
40
-            if interchange_in_function(func) { changed = true; }
42
+            if interchange_in_function(func) {
43
+                changed = true;
44
+            }
4145
         }
4246
         changed
4347
     }
@@ -54,8 +58,12 @@ fn interchange_in_function(func: &mut Function) -> bool {
5458
 
5559
         // Both loops must have a recognized counted-loop structure:
5660
         // header(%iv) → cmp_block(icmp, condBr) → body → latch(iadd, br header)
57
-        let Some(outer_shape) = detect_loop_shape(func, outer, &preds) else { continue };
58
-        let Some(inner_shape) = detect_loop_shape(func, inner, &preds) else { continue };
61
+        let Some(outer_shape) = detect_loop_shape(func, outer, &preds) else {
62
+            continue;
63
+        };
64
+        let Some(inner_shape) = detect_loop_shape(func, inner, &preds) else {
65
+            continue;
66
+        };
5967
 
6068
         // Check profitability: is the outer IV used as the first (fast)
6169
         // subscript of a multi-dimensional array GEP?
@@ -80,11 +88,11 @@ fn interchange_in_function(func: &mut Function) -> bool {
8088
 struct LoopShape {
8189
     header: BlockId,
8290
     cmp_block: BlockId,
83
-    iv: ValueId,          // block param on header
84
-    bound: ValueId,       // the upper-bound value in the comparison
91
+    iv: ValueId,    // block param on header
92
+    bound: ValueId, // the upper-bound value in the comparison
8593
     latch: BlockId,
8694
     /// The value passed to the header from the preheader (initial IV).
87
-    init_arg_idx: usize,  // index in preheader's branch args
95
+    init_arg_idx: usize, // index in preheader's branch args
8896
 }
8997
 
9098
 fn detect_loop_shape(
@@ -96,16 +104,22 @@ fn detect_loop_shape(
96104
     let hdr = func.block(header);
97105
 
98106
     // Header must have exactly 1 block param (the IV).
99
-    if hdr.params.len() != 1 { return None; }
107
+    if hdr.params.len() != 1 {
108
+        return None;
109
+    }
100110
     let iv = hdr.params[0].id;
101111
 
102112
     // Header must be a relay (0 instructions, branch to cmp_block).
103
-    if !hdr.insts.is_empty() { return None; }
113
+    if !hdr.insts.is_empty() {
114
+        return None;
115
+    }
104116
     let cmp_block = match &hdr.terminator {
105117
         Some(Terminator::Branch(t, args)) if args.is_empty() => *t,
106118
         _ => return None,
107119
     };
108
-    if !node.body.contains(&cmp_block) { return None; }
120
+    if !node.body.contains(&cmp_block) {
121
+        return None;
122
+    }
109123
 
110124
     // Cmp block must have icmp + condBr.
111125
     let cmp_blk = func.block(cmp_block);
@@ -114,15 +128,20 @@ fn detect_loop_shape(
114128
         for inst in &cmp_blk.insts {
115129
             if let InstKind::ICmp(_, a, b) = &inst.kind {
116130
                 // One operand should be the IV, the other is the bound.
117
-                if *a == iv { found_bound = Some(*b); }
118
-                else if *b == iv { found_bound = Some(*a); }
131
+                if *a == iv {
132
+                    found_bound = Some(*b);
133
+                } else if *b == iv {
134
+                    found_bound = Some(*a);
135
+                }
119136
             }
120137
         }
121138
         found_bound?
122139
     };
123140
 
124141
     // Find the single latch.
125
-    if node.latches.len() != 1 { return None; }
142
+    if node.latches.len() != 1 {
143
+        return None;
144
+    }
126145
     let latch = node.latches[0];
127146
 
128147
     Some(LoopShape {
@@ -185,7 +204,9 @@ fn uses_iv_in_fast_position(
185204
     _inner_iv: ValueId,
186205
 ) -> bool {
187206
     // Find the instruction that produces `offset`.
188
-    let Some(inst) = find_inst(func, offset) else { return false };
207
+    let Some(inst) = find_inst(func, offset) else {
208
+        return false;
209
+    };
189210
 
190211
     // The offset should be an iadd of two parts.
191212
     let (a, b) = match &inst.kind {
@@ -199,9 +220,13 @@ fn uses_iv_in_fast_position(
199220
     let b_uses_mul = trace_involves_mul(func, b);
200221
 
201222
     // The fast part is the one WITHOUT multiplication.
202
-    let fast_part = if !a_uses_mul && b_uses_mul { a }
203
-                    else if a_uses_mul && !b_uses_mul { b }
204
-                    else { return false };
223
+    let fast_part = if !a_uses_mul && b_uses_mul {
224
+        a
225
+    } else if a_uses_mul && !b_uses_mul {
226
+        b
227
+    } else {
228
+        return false;
229
+    };
205230
 
206231
     // Does the fast part trace back to the outer IV?
207232
     traces_to_iv(func, fast_part, outer_iv)
@@ -209,11 +234,14 @@ fn uses_iv_in_fast_position(
209234
 
210235
 /// Check if a value's computation involves an IMul somewhere.
211236
 fn trace_involves_mul(func: &Function, val: ValueId) -> bool {
212
-    let Some(inst) = find_inst(func, val) else { return false };
237
+    let Some(inst) = find_inst(func, val) else {
238
+        return false;
239
+    };
213240
     match &inst.kind {
214241
         InstKind::IMul(..) => true,
215
-        InstKind::IAdd(a, b) | InstKind::ISub(a, b) =>
216
-            trace_involves_mul(func, *a) || trace_involves_mul(func, *b),
242
+        InstKind::IAdd(a, b) | InstKind::ISub(a, b) => {
243
+            trace_involves_mul(func, *a) || trace_involves_mul(func, *b)
244
+        }
217245
         InstKind::IntExtend(a, _, _) => trace_involves_mul(func, *a),
218246
         _ => false,
219247
     }
@@ -221,8 +249,12 @@ fn trace_involves_mul(func: &Function, val: ValueId) -> bool {
221249
 
222250
 /// Check if a value traces back to a specific IV (through isub, int_extend).
223251
 fn traces_to_iv(func: &Function, val: ValueId, iv: ValueId) -> bool {
224
-    if val == iv { return true; }
225
-    let Some(inst) = find_inst(func, val) else { return false };
252
+    if val == iv {
253
+        return true;
254
+    }
255
+    let Some(inst) = find_inst(func, val) else {
256
+        return false;
257
+    };
226258
     match &inst.kind {
227259
         InstKind::ISub(a, _) => traces_to_iv(func, *a, iv),
228260
         InstKind::IntExtend(a, _, _) => traces_to_iv(func, *a, iv),
@@ -234,7 +266,9 @@ fn traces_to_iv(func: &Function, val: ValueId, iv: ValueId) -> bool {
234266
 fn find_inst(func: &Function, vid: ValueId) -> Option<&Inst> {
235267
     for block in &func.blocks {
236268
         for inst in &block.insts {
237
-            if inst.id == vid { return Some(inst); }
269
+            if inst.id == vid {
270
+                return Some(inst);
271
+            }
238272
         }
239273
     }
240274
     None
@@ -253,7 +287,9 @@ fn is_interchange_legal(
253287
 
254288
 /// Trace through a GEP chain to find the base array pointer.
255289
 fn trace_gep_base(func: &Function, ptr: ValueId) -> Option<ValueId> {
256
-    let Some(inst) = find_inst(func, ptr) else { return Some(ptr); };
290
+    let Some(inst) = find_inst(func, ptr) else {
291
+        return Some(ptr);
292
+    };
257293
     match &inst.kind {
258294
         InstKind::GetElementPtr(base, _) => Some(*base),
259295
         _ => Some(ptr),
@@ -277,7 +313,12 @@ fn do_interchange(func: &mut Function, outer: &LoopShape, inner: &LoopShape) {
277313
                     break;
278314
                 }
279315
             }
280
-            if let Some(Terminator::CondBranch { true_dest, false_dest, .. }) = &block.terminator {
316
+            if let Some(Terminator::CondBranch {
317
+                true_dest,
318
+                false_dest,
319
+                ..
320
+            }) = &block.terminator
321
+            {
281322
                 if *true_dest == outer.header || *false_dest == outer.header {
282323
                     // Could be a condBr preheader from preheader insertion
283324
                     // but we need the unconditional one.
@@ -286,7 +327,9 @@ fn do_interchange(func: &mut Function, outer: &LoopShape, inner: &LoopShape) {
286327
         }
287328
         ph
288329
     };
289
-    let Some(outer_ph) = outer_preheader else { return; };
330
+    let Some(outer_ph) = outer_preheader else {
331
+        return;
332
+    };
290333
 
291334
     // Find the block that branches to the inner header with the inner
292335
     // IV init value (this is the outer loop's "body entry" block).
@@ -299,7 +342,12 @@ fn do_interchange(func: &mut Function, outer: &LoopShape, inner: &LoopShape) {
299342
                     break;
300343
                 }
301344
             }
302
-            if let Some(Terminator::CondBranch { true_dest, true_args, .. }) = &block.terminator {
345
+            if let Some(Terminator::CondBranch {
346
+                true_dest,
347
+                true_args,
348
+                ..
349
+            }) = &block.terminator
350
+            {
303351
                 if *true_dest == inner.header && !true_args.is_empty() {
304352
                     ie = Some(block.id);
305353
                     break;
@@ -308,13 +356,19 @@ fn do_interchange(func: &mut Function, outer: &LoopShape, inner: &LoopShape) {
308356
         }
309357
         ie
310358
     };
311
-    let Some(inner_entry_block) = inner_entry else { return; };
359
+    let Some(inner_entry_block) = inner_entry else {
360
+        return;
361
+    };
312362
 
313363
     // Get current init values.
314364
     let outer_init = get_branch_arg_to(func, outer_ph, outer.header, 0);
315365
     let inner_init = get_branch_arg_to(func, inner_entry_block, inner.header, 0);
316
-    let Some(outer_init_val) = outer_init else { return };
317
-    let Some(inner_init_val) = inner_init else { return };
366
+    let Some(outer_init_val) = outer_init else {
367
+        return;
368
+    };
369
+    let Some(inner_init_val) = inner_init else {
370
+        return;
371
+    };
318372
 
319373
     // Swap init values: outer preheader now passes inner's init to
320374
     // outer's header, and inner entry now passes outer's init to
@@ -332,10 +386,20 @@ fn get_branch_arg_to(func: &Function, from: BlockId, to: BlockId, idx: usize) ->
332386
     let block = func.block(from);
333387
     match &block.terminator {
334388
         Some(Terminator::Branch(dest, args)) if *dest == to => args.get(idx).copied(),
335
-        Some(Terminator::CondBranch { true_dest, true_args, false_dest, false_args, .. }) => {
336
-            if *true_dest == to { true_args.get(idx).copied() }
337
-            else if *false_dest == to { false_args.get(idx).copied() }
338
-            else { None }
389
+        Some(Terminator::CondBranch {
390
+            true_dest,
391
+            true_args,
392
+            false_dest,
393
+            false_args,
394
+            ..
395
+        }) => {
396
+            if *true_dest == to {
397
+                true_args.get(idx).copied()
398
+            } else if *false_dest == to {
399
+                false_args.get(idx).copied()
400
+            } else {
401
+                None
402
+            }
339403
         }
340404
         _ => None,
341405
     }
@@ -346,18 +410,35 @@ fn set_branch_arg_to(func: &mut Function, from: BlockId, to: BlockId, idx: usize
346410
     let block = func.block_mut(from);
347411
     match &mut block.terminator {
348412
         Some(Terminator::Branch(dest, args)) if *dest == to => {
349
-            if idx < args.len() { args[idx] = val; }
413
+            if idx < args.len() {
414
+                args[idx] = val;
415
+            }
350416
         }
351
-        Some(Terminator::CondBranch { true_dest, true_args, false_dest, false_args, .. }) => {
352
-            if *true_dest == to && idx < true_args.len() { true_args[idx] = val; }
353
-            else if *false_dest == to && idx < false_args.len() { false_args[idx] = val; }
417
+        Some(Terminator::CondBranch {
418
+            true_dest,
419
+            true_args,
420
+            false_dest,
421
+            false_args,
422
+            ..
423
+        }) => {
424
+            if *true_dest == to && idx < true_args.len() {
425
+                true_args[idx] = val;
426
+            } else if *false_dest == to && idx < false_args.len() {
427
+                false_args[idx] = val;
428
+            }
354429
         }
355430
         _ => {}
356431
     }
357432
 }
358433
 
359434
 /// Swap the bound value in a comparison block's ICmp instruction.
360
-fn swap_bound(func: &mut Function, cmp_block: BlockId, iv: ValueId, old_bound: ValueId, new_bound: ValueId) {
435
+fn swap_bound(
436
+    func: &mut Function,
437
+    cmp_block: BlockId,
438
+    iv: ValueId,
439
+    old_bound: ValueId,
440
+    new_bound: ValueId,
441
+) {
361442
     let block = func.block_mut(cmp_block);
362443
     for inst in &mut block.insts {
363444
         if let InstKind::ICmp(_op, a, b) = &mut inst.kind {
@@ -380,12 +461,16 @@ fn swap_bound(func: &mut Function, cmp_block: BlockId, iv: ValueId, old_bound: V
380461
 mod tests {
381462
     use super::*;
382463
     use crate::ir::types::IrType;
464
+    use crate::lexer::{Position, Span};
383465
     use crate::opt::pass::Pass;
384
-    use crate::lexer::{Span, Position};
385466
 
386467
     fn span() -> Span {
387468
         let pos = Position { line: 0, col: 0 };
388
-        Span { file_id: 0, start: pos, end: pos }
469
+        Span {
470
+            file_id: 0,
471
+            start: pos,
472
+            end: pos,
473
+        }
389474
     }
390475
 
391476
     #[test]
src/opt/licm.rsmodified
431 lines changed — click to load
@@ -45,7 +45,7 @@
4545
 
4646
 use super::alias::{self, AliasResult};
4747
 use super::pass::Pass;
48
-use super::util::{find_natural_loops, predecessors, inst_uses, NaturalLoop};
48
+use super::util::{find_natural_loops, inst_uses, predecessors, NaturalLoop};
4949
 use crate::ir::inst::*;
5050
 use std::collections::{HashMap, HashSet};
5151
 
@@ -140,7 +140,9 @@ fn licm_function(func: &mut Function) -> bool {
140140
     let pruned = super::util::prune_unreachable(func);
141141
 
142142
     let loops = find_natural_loops(func);
143
-    if loops.is_empty() { return pruned; }
143
+    if loops.is_empty() {
144
+        return pruned;
145
+    }
144146
 
145147
     let preds = predecessors(func);
146148
     let mut any_hoisted = pruned;
@@ -152,14 +154,18 @@ fn licm_function(func: &mut Function) -> bool {
152154
     // we'd "rebuild per iteration" — that was always aspirational
153155
     // and would only matter if a future variant of LICM started
154156
     // mutating the block vector.
155
-    let block_index: HashMap<BlockId, usize> = func.blocks.iter()
157
+    let block_index: HashMap<BlockId, usize> = func
158
+        .blocks
159
+        .iter()
156160
         .enumerate()
157161
         .map(|(i, b)| (b.id, i))
158162
         .collect();
159163
 
160164
     for lp in &loops {
161165
         // Need a preheader to hoist into.
162
-        let Some(ph_id) = find_preheader(func, lp, &preds) else { continue; };
166
+        let Some(ph_id) = find_preheader(func, lp, &preds) else {
167
+            continue;
168
+        };
163169
 
164170
         // Iteratively find invariant instructions until a full pass
165171
         // turns up nothing new. After each round we mark the hoisted
@@ -170,7 +176,9 @@ fn licm_function(func: &mut Function) -> bool {
170176
         loop {
171177
             let mut hoists: Vec<Hoist> = Vec::new();
172178
             for (bi, block) in func.blocks.iter().enumerate() {
173
-                if !lp.body.contains(&block.id) { continue; }
179
+                if !lp.body.contains(&block.id) {
180
+                    continue;
181
+                }
174182
                 for (ii, inst) in block.insts.iter().enumerate() {
175183
                     if !loop_defs.contains(&inst.id) {
176184
                         // Already hoisted (we mark it removed from
@@ -181,16 +189,25 @@ fn licm_function(func: &mut Function) -> bool {
181189
                     // not in the loop_defs set (i.e., previously
182190
                     // hoisted, or defined outside).
183191
                     let operands = inst_uses(&inst.kind);
184
-                    if operands.iter().any(|v| loop_defs.contains(v)) { continue; }
192
+                    if operands.iter().any(|v| loop_defs.contains(v)) {
193
+                        continue;
194
+                    }
185195
                     let hoistable = match &inst.kind {
186196
                         InstKind::Load(ptr) => load_is_loop_invariant(func, lp, inst.id, *ptr),
187197
                         _ => is_non_memory_hoist_candidate(&inst.kind),
188198
                     };
189
-                    if !hoistable { continue; }
190
-                    hoists.push(Hoist { block_idx: bi, inst_idx: ii });
199
+                    if !hoistable {
200
+                        continue;
201
+                    }
202
+                    hoists.push(Hoist {
203
+                        block_idx: bi,
204
+                        inst_idx: ii,
205
+                    });
191206
                 }
192207
             }
193
-            if hoists.is_empty() { break; }
208
+            if hoists.is_empty() {
209
+                break;
210
+            }
194211
 
195212
             // Apply hoists: remove from source blocks (in reverse
196213
             // index order so earlier indices remain valid), then
@@ -241,12 +258,16 @@ fn licm_function(func: &mut Function) -> bool {
241258
 pub struct Licm;
242259
 
243260
 impl Pass for Licm {
244
-    fn name(&self) -> &'static str { "licm" }
261
+    fn name(&self) -> &'static str {
262
+        "licm"
263
+    }
245264
 
246265
     fn run(&self, module: &mut Module) -> bool {
247266
         let mut changed = false;
248267
         for func in &mut module.functions {
249
-            if licm_function(func) { changed = true; }
268
+            if licm_function(func) {
269
+                changed = true;
270
+            }
250271
         }
251272
         changed
252273
     }
@@ -255,12 +276,16 @@ impl Pass for Licm {
255276
 #[cfg(test)]
256277
 mod tests {
257278
     use super::*;
258
-    use crate::ir::types::{IrType, IntWidth};
259
-    use crate::lexer::{Span, Position};
279
+    use crate::ir::types::{IntWidth, IrType};
280
+    use crate::lexer::{Position, Span};
260281
 
261282
     fn dummy_span() -> Span {
262283
         let p = Position { line: 1, col: 1 };
263
-        Span { start: p, end: p, file_id: 0 }
284
+        Span {
285
+            start: p,
286
+            end: p,
287
+            file_id: 0,
288
+        }
264289
     }
265290
 
266291
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
@@ -318,7 +343,10 @@ mod tests {
318343
         // Header.
319344
         let header = f.create_block("header");
320345
         let i_param = f.next_value_id();
321
-        f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
346
+        f.block_mut(header).params.push(BlockParam {
347
+            id: i_param,
348
+            ty: IrType::Int(IntWidth::I32),
349
+        });
322350
         let k = f.next_value_id();
323351
         let tmp = f.next_value_id();
324352
         let done = f.next_value_id();
@@ -344,7 +372,10 @@ mod tests {
344372
         // Latch.
345373
         let latch = f.create_block("latch");
346374
         let i_in = f.next_value_id();
347
-        f.block_mut(latch).params.push(BlockParam { id: i_in, ty: IrType::Int(IntWidth::I32) });
375
+        f.block_mut(latch).params.push(BlockParam {
376
+            id: i_in,
377
+            ty: IrType::Int(IntWidth::I32),
378
+        });
348379
         let one = f.next_value_id();
349380
         let next = f.next_value_id();
350381
         f.block_mut(latch).insts.push(Inst {
@@ -389,11 +420,20 @@ mod tests {
389420
         let entry_block = f.block(f.entry);
390421
         // The const(5) should now live in the entry block (which is
391422
         // the natural preheader), not the header.
392
-        let in_entry_const5 = entry_block.insts.iter().any(|i| matches!(i.kind, InstKind::ConstInt(5, IntWidth::I32)));
393
-        assert!(in_entry_const5, "const(5) should be hoisted into preheader (entry)");
423
+        let in_entry_const5 = entry_block
424
+            .insts
425
+            .iter()
426
+            .any(|i| matches!(i.kind, InstKind::ConstInt(5, IntWidth::I32)));
427
+        assert!(
428
+            in_entry_const5,
429
+            "const(5) should be hoisted into preheader (entry)"
430
+        );
394431
 
395432
         let header_block = f.block(header);
396
-        let in_header_const5 = header_block.insts.iter().any(|i| matches!(i.kind, InstKind::ConstInt(5, IntWidth::I32)));
433
+        let in_header_const5 = header_block
434
+            .insts
435
+            .iter()
436
+            .any(|i| matches!(i.kind, InstKind::ConstInt(5, IntWidth::I32)));
397437
         assert!(!in_header_const5, "const(5) should be removed from header");
398438
     }
399439
 
@@ -405,8 +445,14 @@ mod tests {
405445
         Licm.run(&mut m);
406446
         let f = &m.functions[0];
407447
         let header_block = f.block(header);
408
-        let header_has_iadd = header_block.insts.iter().any(|i| matches!(i.kind, InstKind::IAdd(..)));
409
-        assert!(header_has_iadd, "IAdd(i_param, k) must remain in the header");
448
+        let header_has_iadd = header_block
449
+            .insts
450
+            .iter()
451
+            .any(|i| matches!(i.kind, InstKind::IAdd(..)));
452
+        assert!(
453
+            header_has_iadd,
454
+            "IAdd(i_param, k) must remain in the header"
455
+        );
410456
     }
411457
 
412458
     #[test]
@@ -459,7 +505,10 @@ mod tests {
459505
 
460506
         let header = f.create_block("header");
461507
         let i_param = f.next_value_id();
462
-        f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
508
+        f.block_mut(header).params.push(BlockParam {
509
+            id: i_param,
510
+            ty: IrType::Int(IntWidth::I32),
511
+        });
463512
         let v = f.next_value_id();
464513
         f.block_mut(header).insts.push(Inst {
465514
             id: v,
@@ -503,9 +552,14 @@ mod tests {
503552
         // The Load must still be in the header after LICM.
504553
         let f = &m.functions[0];
505554
         let header_block = f.block(header);
506
-        let load_in_header = header_block.insts.iter()
555
+        let load_in_header = header_block
556
+            .insts
557
+            .iter()
507558
             .any(|i| matches!(i.kind, InstKind::Load(_)));
508
-        assert!(load_in_header, "ambiguous loop load should not have been hoisted");
559
+        assert!(
560
+            load_in_header,
561
+            "ambiguous loop load should not have been hoisted"
562
+        );
509563
     }
510564
 
511565
     #[test]
@@ -554,7 +608,10 @@ mod tests {
554608
 
555609
         let header = f.create_block("header");
556610
         let i_param = f.next_value_id();
557
-        f.block_mut(header).params.push(BlockParam { id: i_param, ty: IrType::Int(IntWidth::I32) });
611
+        f.block_mut(header).params.push(BlockParam {
612
+            id: i_param,
613
+            ty: IrType::Int(IntWidth::I32),
614
+        });
558615
         let v = f.next_value_id();
559616
         f.block_mut(header).insts.push(Inst {
560617
             id: v,
@@ -584,7 +641,10 @@ mod tests {
584641
 
585642
         m.add_function(f);
586643
 
587
-        assert!(Licm.run(&mut m), "LICM should report that it hoisted the loop-invariant load");
644
+        assert!(
645
+            Licm.run(&mut m),
646
+            "LICM should report that it hoisted the loop-invariant load"
647
+        );
588648
 
589649
         // The Load must have moved out of the header — into the
590650
         // preheader or the entry block (LICM hoists into the
@@ -596,14 +656,20 @@ mod tests {
596656
             .insts
597657
             .iter()
598658
             .any(|i| matches!(i.kind, InstKind::Load(_)));
599
-        assert!(!load_still_in_header, "invariant load should have left the header");
659
+        assert!(
660
+            !load_still_in_header,
661
+            "invariant load should have left the header"
662
+        );
600663
         let load_somewhere_else = f
601664
             .blocks
602665
             .iter()
603666
             .filter(|b| b.id != header)
604667
             .flat_map(|b| b.insts.iter())
605668
             .any(|i| matches!(i.kind, InstKind::Load(_)));
606
-        assert!(load_somewhere_else, "invariant load should have been placed in a dominating block");
669
+        assert!(
670
+            load_somewhere_else,
671
+            "invariant load should have been placed in a dominating block"
672
+        );
607673
     }
608674
 
609675
     #[test]
@@ -625,8 +691,16 @@ mod tests {
625691
         let mut m = Module::new("t".into());
626692
         let mut f = Function::new("f".into(), params, IrType::Void);
627693
 
628
-        let init = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
629
-        let limit = push(&mut f, InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32));
694
+        let init = push(
695
+            &mut f,
696
+            InstKind::ConstInt(0, IntWidth::I32),
697
+            IrType::Int(IntWidth::I32),
698
+        );
699
+        let limit = push(
700
+            &mut f,
701
+            InstKind::ConstInt(10, IntWidth::I32),
702
+            IrType::Int(IntWidth::I32),
703
+        );
630704
 
631705
         let header = f.create_block("header");
632706
         let i_param = f.next_value_id();
@@ -685,7 +759,10 @@ mod tests {
685759
 
686760
         m.add_function(f);
687761
 
688
-        assert!(Licm.run(&mut m), "LICM should hoist the invariant dummy-arg load");
762
+        assert!(
763
+            Licm.run(&mut m),
764
+            "LICM should hoist the invariant dummy-arg load"
765
+        );
689766
 
690767
         let f = &m.functions[0];
691768
         let entry_block = f.block(f.entry);
@@ -721,16 +798,22 @@ mod tests {
721798
         let init = f.next_value_id();
722799
         let entry = f.entry;
723800
         f.block_mut(entry).insts.push(Inst {
724
-            id: a, kind: InstKind::ConstInt(3, IntWidth::I32),
725
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
801
+            id: a,
802
+            kind: InstKind::ConstInt(3, IntWidth::I32),
803
+            ty: IrType::Int(IntWidth::I32),
804
+            span: dummy_span(),
726805
         });
727806
         f.block_mut(entry).insts.push(Inst {
728
-            id: bv, kind: InstKind::ConstInt(4, IntWidth::I32),
729
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
807
+            id: bv,
808
+            kind: InstKind::ConstInt(4, IntWidth::I32),
809
+            ty: IrType::Int(IntWidth::I32),
810
+            span: dummy_span(),
730811
         });
731812
         f.block_mut(entry).insts.push(Inst {
732
-            id: init, kind: InstKind::ConstInt(0, IntWidth::I32),
733
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
813
+            id: init,
814
+            kind: InstKind::ConstInt(0, IntWidth::I32),
815
+            ty: IrType::Int(IntWidth::I32),
816
+            span: dummy_span(),
734817
         });
735818
 
736819
         // Header: i_param, then `prod = a * b` (invariant), then
@@ -738,44 +821,58 @@ mod tests {
738821
         let header = f.create_block("header");
739822
         let i_param = f.next_value_id();
740823
         f.block_mut(header).params.push(BlockParam {
741
-            id: i_param, ty: IrType::Int(IntWidth::I32),
824
+            id: i_param,
825
+            ty: IrType::Int(IntWidth::I32),
742826
         });
743827
         let prod = f.next_value_id();
744828
         let tmp = f.next_value_id();
745829
         let limit = f.next_value_id();
746830
         let done = f.next_value_id();
747831
         f.block_mut(header).insts.push(Inst {
748
-            id: prod, kind: InstKind::IMul(a, bv),
749
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
832
+            id: prod,
833
+            kind: InstKind::IMul(a, bv),
834
+            ty: IrType::Int(IntWidth::I32),
835
+            span: dummy_span(),
750836
         });
751837
         f.block_mut(header).insts.push(Inst {
752
-            id: tmp, kind: InstKind::IAdd(i_param, prod),
753
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
838
+            id: tmp,
839
+            kind: InstKind::IAdd(i_param, prod),
840
+            ty: IrType::Int(IntWidth::I32),
841
+            span: dummy_span(),
754842
         });
755843
         f.block_mut(header).insts.push(Inst {
756
-            id: limit, kind: InstKind::ConstInt(10, IntWidth::I32),
757
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
844
+            id: limit,
845
+            kind: InstKind::ConstInt(10, IntWidth::I32),
846
+            ty: IrType::Int(IntWidth::I32),
847
+            span: dummy_span(),
758848
         });
759849
         f.block_mut(header).insts.push(Inst {
760
-            id: done, kind: InstKind::ICmp(CmpOp::Ge, i_param, limit),
761
-            ty: IrType::Bool, span: dummy_span(),
850
+            id: done,
851
+            kind: InstKind::ICmp(CmpOp::Ge, i_param, limit),
852
+            ty: IrType::Bool,
853
+            span: dummy_span(),
762854
         });
763855
 
764856
         // Latch: increment i and loop back.
765857
         let latch = f.create_block("latch");
766858
         let i_in = f.next_value_id();
767859
         f.block_mut(latch).params.push(BlockParam {
768
-            id: i_in, ty: IrType::Int(IntWidth::I32),
860
+            id: i_in,
861
+            ty: IrType::Int(IntWidth::I32),
769862
         });
770863
         let one = f.next_value_id();
771864
         let next = f.next_value_id();
772865
         f.block_mut(latch).insts.push(Inst {
773
-            id: one, kind: InstKind::ConstInt(1, IntWidth::I32),
774
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
866
+            id: one,
867
+            kind: InstKind::ConstInt(1, IntWidth::I32),
868
+            ty: IrType::Int(IntWidth::I32),
869
+            span: dummy_span(),
775870
         });
776871
         f.block_mut(latch).insts.push(Inst {
777
-            id: next, kind: InstKind::IAdd(i_in, one),
778
-            ty: IrType::Int(IntWidth::I32), span: dummy_span(),
872
+            id: next,
873
+            kind: InstKind::IAdd(i_in, one),
874
+            ty: IrType::Int(IntWidth::I32),
875
+            span: dummy_span(),
779876
         });
780877
         f.block_mut(latch).terminator = Some(Terminator::Branch(header, vec![next]));
781878
 
@@ -785,8 +882,10 @@ mod tests {
785882
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![init]));
786883
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
787884
             cond: done,
788
-            true_dest: exit, true_args: vec![],
789
-            false_dest: latch, false_args: vec![i_param],
885
+            true_dest: exit,
886
+            true_args: vec![],
887
+            false_dest: latch,
888
+            false_args: vec![i_param],
790889
         });
791890
 
792891
         m.add_function(f);
@@ -797,23 +896,35 @@ mod tests {
797896
         // The IMul must have moved out of the header into the entry
798897
         // (the natural preheader).
799898
         let header_block = f.block(header);
800
-        let imul_in_header = header_block.insts.iter()
899
+        let imul_in_header = header_block
900
+            .insts
901
+            .iter()
801902
             .any(|i| matches!(i.kind, InstKind::IMul(..)));
802
-        assert!(!imul_in_header,
903
+        assert!(
904
+            !imul_in_header,
803905
             "invariant IMul should be hoisted out of the header: {:?}",
804
-            header_block.insts);
906
+            header_block.insts
907
+        );
805908
 
806909
         let entry_block = f.block(f.entry);
807
-        let imul_in_entry = entry_block.insts.iter()
910
+        let imul_in_entry = entry_block
911
+            .insts
912
+            .iter()
808913
             .any(|i| matches!(i.kind, InstKind::IMul(..)));
809
-        assert!(imul_in_entry,
914
+        assert!(
915
+            imul_in_entry,
810916
             "invariant IMul should land in entry/preheader after hoist: {:?}",
811
-            entry_block.insts);
917
+            entry_block.insts
918
+        );
812919
 
813920
         // The loop-dependent IAdd must NOT have moved.
814
-        let iadd_in_header = header_block.insts.iter()
921
+        let iadd_in_header = header_block
922
+            .insts
923
+            .iter()
815924
             .any(|i| matches!(i.kind, InstKind::IAdd(_, _)));
816
-        assert!(iadd_in_header,
817
-            "loop-dependent IAdd(i_param, prod) should still be in the header");
925
+        assert!(
926
+            iadd_in_header,
927
+            "loop-dependent IAdd(i_param, prod) should still be in the header"
928
+        );
818929
     }
819930
 }
src/opt/loop_tree.rsmodified
368 lines changed — click to load
@@ -5,9 +5,9 @@
55
 //! parent, and children, so passes like interchange can find
66
 //! perfectly-nested pairs and unswitching can target innermost loops.
77
 
8
-use std::collections::{HashMap, HashSet};
98
 use crate::ir::inst::{BlockId, Function};
109
 use crate::ir::walk::find_natural_loops;
10
+use std::collections::{HashMap, HashSet};
1111
 
1212
 /// Unique identifier for a loop in the tree.
1313
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -37,7 +37,8 @@ pub struct LoopTree {
3737
 impl LoopTree {
3838
     /// Return the IDs of all innermost (leaf) loops — loops with no children.
3939
     pub fn innermost_loops(&self) -> Vec<LoopId> {
40
-        self.nodes.iter()
40
+        self.nodes
41
+            .iter()
4142
             .filter(|n| n.children.is_empty())
4243
             .map(|n| n.id)
4344
             .collect()
@@ -50,7 +51,8 @@ impl LoopTree {
5051
 
5152
     /// Nesting depth of a block (0 if not in any loop).
5253
     pub fn loop_depth(&self, block: BlockId) -> u32 {
53
-        self.block_to_loop.get(&block)
54
+        self.block_to_loop
55
+            .get(&block)
5456
             .map(|lid| self.node(*lid).depth)
5557
             .unwrap_or(0)
5658
     }
@@ -67,7 +69,9 @@ impl LoopTree {
6769
     pub fn perfectly_nested_pairs(&self, func: &Function) -> Vec<(LoopId, LoopId)> {
6870
         let mut pairs = Vec::new();
6971
         for node in &self.nodes {
70
-            if node.children.len() != 1 { continue; }
72
+            if node.children.len() != 1 {
73
+                continue;
74
+            }
7175
             let child_id = node.children[0];
7276
             let child = self.node(child_id);
7377
 
@@ -78,16 +82,17 @@ impl LoopTree {
7882
             // - the outer latch (increment + branch)
7983
             // - the outer "body" block that just branches to the inner preheader
8084
             // Everything else must be part of the inner loop.
81
-            let outer_only: Vec<BlockId> = node.body.iter()
85
+            let outer_only: Vec<BlockId> = node
86
+                .body
87
+                .iter()
8288
                 .filter(|b| !child.body.contains(b))
8389
                 .copied()
8490
                 .collect();
8591
 
8692
             // Conservative check: outer-only blocks should have very few
8793
             // instructions total (header relay + cmp + latch + body-entry).
88
-            let total_outer_insts: usize = outer_only.iter()
89
-                .map(|&b| func.block(b).insts.len())
90
-                .sum();
94
+            let total_outer_insts: usize =
95
+                outer_only.iter().map(|&b| func.block(b).insts.len()).sum();
9196
 
9297
             // A typical Fortran DO nest has ~4-6 instructions in the
9398
             // outer shell (const bound, icmp, iadd). Allow up to 10
@@ -120,8 +125,10 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
120125
     indexed.sort_by(|a, b| b.1.body.len().cmp(&a.1.body.len()));
121126
 
122127
     // Build nodes with stable IDs (original discovery order).
123
-    let mut nodes: Vec<LoopTreeNode> = natural.iter().enumerate().map(|(i, nl)| {
124
-        LoopTreeNode {
128
+    let mut nodes: Vec<LoopTreeNode> = natural
129
+        .iter()
130
+        .enumerate()
131
+        .map(|(i, nl)| LoopTreeNode {
125132
             id: LoopId(i as u32),
126133
             header: nl.header,
127134
             body: nl.body.clone(),
@@ -129,8 +136,8 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
129136
             parent: None,
130137
             children: Vec::new(),
131138
             depth: 0,
132
-        }
133
-    }).collect();
139
+        })
140
+        .collect();
134141
 
135142
     // For each loop, find its parent = the smallest loop that strictly
136143
     // contains it. We iterate in body-size order so we can check
@@ -140,7 +147,9 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
140147
         let mut best_parent: Option<LoopId> = None;
141148
         let mut best_size = usize::MAX;
142149
         for j in 0..n {
143
-            if i == j { continue; }
150
+            if i == j {
151
+                continue;
152
+            }
144153
             // j is a candidate parent if j's body strictly contains i's body.
145154
             if nodes[j].body.len() > nodes[i].body.len()
146155
                 && nodes[i].body.is_subset(&nodes[j].body)
@@ -164,11 +173,17 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
164173
     // Sort children by header for determinism.
165174
     // (Two-step to satisfy the borrow checker: collect sort keys, then sort.)
166175
     for i in 0..n {
167
-        let headers: Vec<(LoopId, u32)> = nodes[i].children.iter()
176
+        let headers: Vec<(LoopId, u32)> = nodes[i]
177
+            .children
178
+            .iter()
168179
             .map(|c| (*c, nodes[c.0 as usize].header.0))
169180
             .collect();
170181
         nodes[i].children.sort_by_key(|c| {
171
-            headers.iter().find(|(id, _)| id == c).map(|(_, h)| *h).unwrap_or(0)
182
+            headers
183
+                .iter()
184
+                .find(|(id, _)| id == c)
185
+                .map(|(_, h)| *h)
186
+                .unwrap_or(0)
172187
         });
173188
     }
174189
 
@@ -189,9 +204,7 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
189204
     // Build block → innermost loop mapping.
190205
     // Process innermost (deepest) loops last so they overwrite parents.
191206
     let mut block_to_loop: HashMap<BlockId, LoopId> = HashMap::new();
192
-    let mut by_depth: Vec<(u32, LoopId)> = nodes.iter()
193
-        .map(|n| (n.depth, n.id))
194
-        .collect();
207
+    let mut by_depth: Vec<(u32, LoopId)> = nodes.iter().map(|n| (n.depth, n.id)).collect();
195208
     by_depth.sort_by_key(|(d, _)| *d);
196209
     for (_, lid) in by_depth {
197210
         for &block in &nodes[lid.0 as usize].body {
@@ -199,7 +212,10 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
199212
         }
200213
     }
201214
 
202
-    LoopTree { nodes, block_to_loop }
215
+    LoopTree {
216
+        nodes,
217
+        block_to_loop,
218
+    }
203219
 }
204220
 
205221
 // ---------------------------------------------------------------------------
@@ -209,13 +225,17 @@ pub fn build_loop_tree(func: &Function) -> LoopTree {
209225
 #[cfg(test)]
210226
 mod tests {
211227
     use super::*;
212
-    use crate::ir::types::{IrType, IntWidth};
213228
     use crate::ir::inst::*;
214
-    use crate::lexer::{Span, Position};
229
+    use crate::ir::types::{IntWidth, IrType};
230
+    use crate::lexer::{Position, Span};
215231
 
216232
     fn span() -> Span {
217233
         let pos = Position { line: 0, col: 0 };
218
-        Span { file_id: 0, start: pos, end: pos }
234
+        Span {
235
+            file_id: 0,
236
+            start: pos,
237
+            end: pos,
238
+        }
219239
     }
220240
 
221241
     /// Build a function with 3-level nested DO loops:
@@ -228,17 +248,17 @@ mod tests {
228248
         let mut f = Function::new("triple".into(), vec![], IrType::Void);
229249
 
230250
         // Create all blocks upfront.
231
-        let outer_hdr   = f.create_block("outer_hdr");
232
-        let outer_cmp   = f.create_block("outer_cmp");
233
-        let inner_hdr   = f.create_block("inner_hdr");
234
-        let inner_cmp   = f.create_block("inner_cmp");
235
-        let deep_hdr    = f.create_block("deep_hdr");
236
-        let deep_cmp    = f.create_block("deep_cmp");
237
-        let body        = f.create_block("body");
238
-        let deep_latch  = f.create_block("deep_latch");
251
+        let outer_hdr = f.create_block("outer_hdr");
252
+        let outer_cmp = f.create_block("outer_cmp");
253
+        let inner_hdr = f.create_block("inner_hdr");
254
+        let inner_cmp = f.create_block("inner_cmp");
255
+        let deep_hdr = f.create_block("deep_hdr");
256
+        let deep_cmp = f.create_block("deep_cmp");
257
+        let body = f.create_block("body");
258
+        let deep_latch = f.create_block("deep_latch");
239259
         let inner_latch = f.create_block("inner_latch");
240260
         let outer_latch = f.create_block("outer_latch");
241
-        let exit        = f.create_block("exit");
261
+        let exit = f.create_block("exit");
242262
 
243263
         let entry = f.entry;
244264
 
@@ -246,53 +266,72 @@ mod tests {
246266
         let one = f.next_value_id();
247267
         f.register_type(one, IrType::Int(IntWidth::I32));
248268
         f.block_mut(entry).insts.push(Inst {
249
-            id: one, ty: IrType::Int(IntWidth::I32), span: span(),
269
+            id: one,
270
+            ty: IrType::Int(IntWidth::I32),
271
+            span: span(),
250272
             kind: InstKind::ConstInt(1, IntWidth::I32),
251273
         });
252274
         f.block_mut(entry).terminator = Some(Terminator::Branch(outer_hdr, vec![one]));
253275
 
254276
         // Helper: add a simple loop level (header with param → cmp → condBr)
255277
         fn add_loop_level(
256
-            f: &mut Function, hdr: BlockId, cmp: BlockId,
257
-            body_target: BlockId, exit_target: BlockId,
258
-            latch: BlockId, init_src: ValueId,
278
+            f: &mut Function,
279
+            hdr: BlockId,
280
+            cmp: BlockId,
281
+            body_target: BlockId,
282
+            exit_target: BlockId,
283
+            latch: BlockId,
284
+            init_src: ValueId,
259285
         ) -> (ValueId, ValueId) {
260286
             // Header: block param
261287
             let iv = f.next_value_id();
262288
             f.register_type(iv, IrType::Int(IntWidth::I32));
263
-            f.block_mut(hdr).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
289
+            f.block_mut(hdr).params.push(BlockParam {
290
+                id: iv,
291
+                ty: IrType::Int(IntWidth::I32),
292
+            });
264293
             f.block_mut(hdr).terminator = Some(Terminator::Branch(cmp, vec![]));
265294
 
266295
             // Cmp: icmp le iv, 10; condBr body, exit
267296
             let bound = f.next_value_id();
268297
             f.register_type(bound, IrType::Int(IntWidth::I32));
269298
             f.block_mut(cmp).insts.push(Inst {
270
-                id: bound, ty: IrType::Int(IntWidth::I32), span: span(),
299
+                id: bound,
300
+                ty: IrType::Int(IntWidth::I32),
301
+                span: span(),
271302
                 kind: InstKind::ConstInt(10, IntWidth::I32),
272303
             });
273304
             let cmp_val = f.next_value_id();
274305
             f.register_type(cmp_val, IrType::Bool);
275306
             f.block_mut(cmp).insts.push(Inst {
276
-                id: cmp_val, ty: IrType::Bool, span: span(),
307
+                id: cmp_val,
308
+                ty: IrType::Bool,
309
+                span: span(),
277310
                 kind: InstKind::ICmp(CmpOp::Le, iv, bound),
278311
             });
279312
             f.block_mut(cmp).terminator = Some(Terminator::CondBranch {
280313
                 cond: cmp_val,
281
-                true_dest: body_target, true_args: vec![],
282
-                false_dest: exit_target, false_args: vec![],
314
+                true_dest: body_target,
315
+                true_args: vec![],
316
+                false_dest: exit_target,
317
+                false_args: vec![],
283318
             });
284319
 
285320
             // Latch: iadd iv, 1; br hdr(next)
286321
             let one_l = f.next_value_id();
287322
             f.register_type(one_l, IrType::Int(IntWidth::I32));
288323
             f.block_mut(latch).insts.push(Inst {
289
-                id: one_l, ty: IrType::Int(IntWidth::I32), span: span(),
324
+                id: one_l,
325
+                ty: IrType::Int(IntWidth::I32),
326
+                span: span(),
290327
                 kind: InstKind::ConstInt(1, IntWidth::I32),
291328
             });
292329
             let next = f.next_value_id();
293330
             f.register_type(next, IrType::Int(IntWidth::I32));
294331
             f.block_mut(latch).insts.push(Inst {
295
-                id: next, ty: IrType::Int(IntWidth::I32), span: span(),
332
+                id: next,
333
+                ty: IrType::Int(IntWidth::I32),
334
+                span: span(),
296335
                 kind: InstKind::IAdd(iv, one_l),
297336
             });
298337
             f.block_mut(latch).terminator = Some(Terminator::Branch(hdr, vec![next]));
@@ -302,15 +341,33 @@ mod tests {
302341
         }
303342
 
304343
         // Outer loop: entry→outer_hdr(1)→outer_cmp→inner_hdr/exit
305
-        let (_, _) = add_loop_level(&mut f, outer_hdr, outer_cmp, inner_hdr, exit, outer_latch, one);
344
+        let (_, _) = add_loop_level(
345
+            &mut f,
346
+            outer_hdr,
347
+            outer_cmp,
348
+            inner_hdr,
349
+            exit,
350
+            outer_latch,
351
+            one,
352
+        );
306353
         // Wire outer_cmp's true branch to pass `one` to inner_hdr
307354
         // (inner loop starts at 1 each outer iteration)
308
-        if let Some(Terminator::CondBranch { true_args, .. }) = &mut f.block_mut(outer_cmp).terminator {
355
+        if let Some(Terminator::CondBranch { true_args, .. }) =
356
+            &mut f.block_mut(outer_cmp).terminator
357
+        {
309358
             true_args.push(one);
310359
         }
311360
 
312361
         // Inner loop
313
-        let (_, _) = add_loop_level(&mut f, inner_hdr, inner_cmp, deep_hdr, inner_latch, inner_latch, one);
362
+        let (_, _) = add_loop_level(
363
+            &mut f,
364
+            inner_hdr,
365
+            inner_cmp,
366
+            deep_hdr,
367
+            inner_latch,
368
+            inner_latch,
369
+            one,
370
+        );
314371
         // Inner latch needs to go to outer_latch after the inner loop exits...
315372
         // Actually inner_latch IS the inner latch (iadd + br inner_hdr). The exit
316373
         // of the inner loop goes to outer_latch. Let me fix: inner_cmp's false goes to outer_latch.
@@ -331,13 +388,17 @@ mod tests {
331388
         let c1 = f.next_value_id();
332389
         f.register_type(c1, IrType::Int(IntWidth::I32));
333390
         f.block_mut(entry).insts.push(Inst {
334
-            id: c1, ty: IrType::Int(IntWidth::I32), span: span(),
391
+            id: c1,
392
+            ty: IrType::Int(IntWidth::I32),
393
+            span: span(),
335394
             kind: InstKind::ConstInt(1, IntWidth::I32),
336395
         });
337396
         let c10 = f.next_value_id();
338397
         f.register_type(c10, IrType::Int(IntWidth::I32));
339398
         f.block_mut(entry).insts.push(Inst {
340
-            id: c10, ty: IrType::Int(IntWidth::I32), span: span(),
399
+            id: c10,
400
+            ty: IrType::Int(IntWidth::I32),
401
+            span: span(),
341402
             kind: InstKind::ConstInt(10, IntWidth::I32),
342403
         });
343404
         f.block_mut(entry).terminator = Some(Terminator::Branch(outer_hdr, vec![c1]));
@@ -347,7 +408,10 @@ mod tests {
347408
             ($f:expr, $hdr:expr, $cmp:expr) => {{
348409
                 let iv = $f.next_value_id();
349410
                 $f.register_type(iv, IrType::Int(IntWidth::I32));
350
-                $f.block_mut($hdr).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
411
+                $f.block_mut($hdr).params.push(BlockParam {
412
+                    id: iv,
413
+                    ty: IrType::Int(IntWidth::I32),
414
+                });
351415
                 $f.block_mut($hdr).terminator = Some(Terminator::Branch($cmp, vec![]));
352416
                 iv
353417
             }};
@@ -357,12 +421,17 @@ mod tests {
357421
                 let cv = $f.next_value_id();
358422
                 $f.register_type(cv, IrType::Bool);
359423
                 $f.block_mut($cmp).insts.push(Inst {
360
-                    id: cv, ty: IrType::Bool, span: span(),
424
+                    id: cv,
425
+                    ty: IrType::Bool,
426
+                    span: span(),
361427
                     kind: InstKind::ICmp(CmpOp::Le, $iv, $bound),
362428
                 });
363429
                 $f.block_mut($cmp).terminator = Some(Terminator::CondBranch {
364
-                    cond: cv, true_dest: $t, true_args: $t_args,
365
-                    false_dest: $fal, false_args: vec![],
430
+                    cond: cv,
431
+                    true_dest: $t,
432
+                    true_args: $t_args,
433
+                    false_dest: $fal,
434
+                    false_args: vec![],
366435
                 });
367436
             }};
368437
         }
@@ -371,7 +440,9 @@ mod tests {
371440
                 let nxt = $f.next_value_id();
372441
                 $f.register_type(nxt, IrType::Int(IntWidth::I32));
373442
                 $f.block_mut($latch).insts.push(Inst {
374
-                    id: nxt, ty: IrType::Int(IntWidth::I32), span: span(),
443
+                    id: nxt,
444
+                    ty: IrType::Int(IntWidth::I32),
445
+                    span: span(),
375446
                     kind: InstKind::IAdd($iv, $one),
376447
                 });
377448
                 $f.block_mut($latch).terminator = Some(Terminator::Branch($hdr, vec![nxt]));
@@ -442,7 +513,11 @@ mod tests {
442513
         let tree = build_loop_tree(&f);
443514
 
444515
         // The body block should map to the innermost loop.
445
-        let body_block = f.blocks.iter().find(|b| b.name.starts_with("body")).unwrap();
516
+        let body_block = f
517
+            .blocks
518
+            .iter()
519
+            .find(|b| b.name.starts_with("body"))
520
+            .unwrap();
446521
         let mapped = tree.block_to_loop.get(&body_block.id);
447522
         assert!(mapped.is_some(), "body block should be in a loop");
448523
         let mapped_node = tree.node(*mapped.unwrap());
src/opt/loop_utils.rsmodified
191 lines changed — click to load
@@ -4,9 +4,9 @@
44
 //! (from unroll.rs) into public shared functions so all loop passes
55
 //! use the same logic.
66
 
7
-use std::collections::{HashMap, HashSet};
87
 use crate::ir::inst::*;
98
 use crate::ir::walk::NaturalLoop;
9
+use std::collections::{HashMap, HashSet};
1010
 
1111
 /// Find the unique preheader for a natural loop, if one exists.
1212
 ///
@@ -28,9 +28,13 @@ pub fn find_preheader(
2828
         .collect();
2929
     outside.sort_by_key(|b| b.0);
3030
     outside.dedup();
31
-    if outside.len() != 1 { return None; }
31
+    if outside.len() != 1 {
32
+        return None;
33
+    }
3234
     let ph = outside[0];
33
-    if ph == lp.header { return None; }
35
+    if ph == lp.header {
36
+        return None;
37
+    }
3438
     let ph_block = func.block(ph);
3539
     match &ph_block.terminator {
3640
         Some(Terminator::Branch(dest, _)) if *dest == lp.header => Some(ph),
@@ -60,8 +64,12 @@ pub fn loop_defined_values(func: &Function, lp: &NaturalLoop) -> HashSet<ValueId
6064
     let mut defs = HashSet::new();
6165
     for &bid in &lp.body {
6266
         let block = func.block(bid);
63
-        for bp in &block.params { defs.insert(bp.id); }
64
-        for inst in &block.insts { defs.insert(inst.id); }
67
+        for bp in &block.params {
68
+            defs.insert(bp.id);
69
+        }
70
+        for inst in &block.insts {
71
+            defs.insert(inst.id);
72
+        }
6573
     }
6674
     defs
6775
 }
@@ -167,60 +175,61 @@ pub fn build_value_map(
167175
 pub fn remap_inst_kind(kind: &InstKind, map: &HashMap<ValueId, ValueId>) -> InstKind {
168176
     let r = |v: &ValueId| *map.get(v).unwrap_or(v);
169177
     match kind {
170
-        InstKind::ConstInt(v, w)     => InstKind::ConstInt(*v, *w),
171
-        InstKind::ConstFloat(v, w)   => InstKind::ConstFloat(*v, *w),
172
-        InstKind::ConstBool(v)       => InstKind::ConstBool(*v),
173
-        InstKind::ConstString(v)     => InstKind::ConstString(v.clone()),
174
-        InstKind::Undef(t)           => InstKind::Undef(t.clone()),
175
-        InstKind::GlobalAddr(s)      => InstKind::GlobalAddr(s.clone()),
176
-        InstKind::IAdd(a, b)  => InstKind::IAdd(r(a), r(b)),
177
-        InstKind::ISub(a, b)  => InstKind::ISub(r(a), r(b)),
178
-        InstKind::IMul(a, b)  => InstKind::IMul(r(a), r(b)),
179
-        InstKind::IDiv(a, b)  => InstKind::IDiv(r(a), r(b)),
180
-        InstKind::IMod(a, b)  => InstKind::IMod(r(a), r(b)),
181
-        InstKind::INeg(a)     => InstKind::INeg(r(a)),
182
-        InstKind::FAdd(a, b)  => InstKind::FAdd(r(a), r(b)),
183
-        InstKind::FSub(a, b)  => InstKind::FSub(r(a), r(b)),
184
-        InstKind::FMul(a, b)  => InstKind::FMul(r(a), r(b)),
185
-        InstKind::FDiv(a, b)  => InstKind::FDiv(r(a), r(b)),
186
-        InstKind::FNeg(a)     => InstKind::FNeg(r(a)),
187
-        InstKind::FAbs(a)     => InstKind::FAbs(r(a)),
188
-        InstKind::FSqrt(a)    => InstKind::FSqrt(r(a)),
189
-        InstKind::FPow(a, b)  => InstKind::FPow(r(a), r(b)),
178
+        InstKind::ConstInt(v, w) => InstKind::ConstInt(*v, *w),
179
+        InstKind::ConstFloat(v, w) => InstKind::ConstFloat(*v, *w),
180
+        InstKind::ConstBool(v) => InstKind::ConstBool(*v),
181
+        InstKind::ConstString(v) => InstKind::ConstString(v.clone()),
182
+        InstKind::Undef(t) => InstKind::Undef(t.clone()),
183
+        InstKind::GlobalAddr(s) => InstKind::GlobalAddr(s.clone()),
184
+        InstKind::IAdd(a, b) => InstKind::IAdd(r(a), r(b)),
185
+        InstKind::ISub(a, b) => InstKind::ISub(r(a), r(b)),
186
+        InstKind::IMul(a, b) => InstKind::IMul(r(a), r(b)),
187
+        InstKind::IDiv(a, b) => InstKind::IDiv(r(a), r(b)),
188
+        InstKind::IMod(a, b) => InstKind::IMod(r(a), r(b)),
189
+        InstKind::INeg(a) => InstKind::INeg(r(a)),
190
+        InstKind::FAdd(a, b) => InstKind::FAdd(r(a), r(b)),
191
+        InstKind::FSub(a, b) => InstKind::FSub(r(a), r(b)),
192
+        InstKind::FMul(a, b) => InstKind::FMul(r(a), r(b)),
193
+        InstKind::FDiv(a, b) => InstKind::FDiv(r(a), r(b)),
194
+        InstKind::FNeg(a) => InstKind::FNeg(r(a)),
195
+        InstKind::FAbs(a) => InstKind::FAbs(r(a)),
196
+        InstKind::FSqrt(a) => InstKind::FSqrt(r(a)),
197
+        InstKind::FPow(a, b) => InstKind::FPow(r(a), r(b)),
190198
         InstKind::ICmp(op, a, b) => InstKind::ICmp(*op, r(a), r(b)),
191199
         InstKind::FCmp(op, a, b) => InstKind::FCmp(*op, r(a), r(b)),
192200
         InstKind::And(a, b) => InstKind::And(r(a), r(b)),
193
-        InstKind::Or(a, b)  => InstKind::Or(r(a), r(b)),
194
-        InstKind::Not(a)    => InstKind::Not(r(a)),
201
+        InstKind::Or(a, b) => InstKind::Or(r(a), r(b)),
202
+        InstKind::Not(a) => InstKind::Not(r(a)),
195203
         InstKind::Select(c, t, f) => InstKind::Select(r(c), r(t), r(f)),
196
-        InstKind::BitAnd(a, b)           => InstKind::BitAnd(r(a), r(b)),
197
-        InstKind::BitOr(a, b)            => InstKind::BitOr(r(a), r(b)),
198
-        InstKind::BitXor(a, b)           => InstKind::BitXor(r(a), r(b)),
199
-        InstKind::BitNot(a)              => InstKind::BitNot(r(a)),
200
-        InstKind::Shl(a, b)              => InstKind::Shl(r(a), r(b)),
201
-        InstKind::LShr(a, b)             => InstKind::LShr(r(a), r(b)),
202
-        InstKind::AShr(a, b)             => InstKind::AShr(r(a), r(b)),
203
-        InstKind::CountLeadingZeros(a)   => InstKind::CountLeadingZeros(r(a)),
204
-        InstKind::CountTrailingZeros(a)  => InstKind::CountTrailingZeros(r(a)),
205
-        InstKind::PopCount(a)            => InstKind::PopCount(r(a)),
206
-        InstKind::IntToFloat(a, w)    => InstKind::IntToFloat(r(a), *w),
207
-        InstKind::FloatToInt(a, w)    => InstKind::FloatToInt(r(a), *w),
208
-        InstKind::FloatExtend(a, w)   => InstKind::FloatExtend(r(a), *w),
209
-        InstKind::FloatTrunc(a, w)    => InstKind::FloatTrunc(r(a), *w),
210
-        InstKind::IntExtend(a, w, s)  => InstKind::IntExtend(r(a), *w, *s),
211
-        InstKind::IntTrunc(a, w)      => InstKind::IntTrunc(r(a), *w),
212
-        InstKind::PtrToInt(a)         => InstKind::PtrToInt(r(a)),
213
-        InstKind::IntToPtr(a, ty)     => InstKind::IntToPtr(r(a), ty.clone()),
214
-        InstKind::Alloca(t)  => InstKind::Alloca(t.clone()),
215
-        InstKind::Load(a)    => InstKind::Load(r(a)),
204
+        InstKind::BitAnd(a, b) => InstKind::BitAnd(r(a), r(b)),
205
+        InstKind::BitOr(a, b) => InstKind::BitOr(r(a), r(b)),
206
+        InstKind::BitXor(a, b) => InstKind::BitXor(r(a), r(b)),
207
+        InstKind::BitNot(a) => InstKind::BitNot(r(a)),
208
+        InstKind::Shl(a, b) => InstKind::Shl(r(a), r(b)),
209
+        InstKind::LShr(a, b) => InstKind::LShr(r(a), r(b)),
210
+        InstKind::AShr(a, b) => InstKind::AShr(r(a), r(b)),
211
+        InstKind::CountLeadingZeros(a) => InstKind::CountLeadingZeros(r(a)),
212
+        InstKind::CountTrailingZeros(a) => InstKind::CountTrailingZeros(r(a)),
213
+        InstKind::PopCount(a) => InstKind::PopCount(r(a)),
214
+        InstKind::IntToFloat(a, w) => InstKind::IntToFloat(r(a), *w),
215
+        InstKind::FloatToInt(a, w) => InstKind::FloatToInt(r(a), *w),
216
+        InstKind::FloatExtend(a, w) => InstKind::FloatExtend(r(a), *w),
217
+        InstKind::FloatTrunc(a, w) => InstKind::FloatTrunc(r(a), *w),
218
+        InstKind::IntExtend(a, w, s) => InstKind::IntExtend(r(a), *w, *s),
219
+        InstKind::IntTrunc(a, w) => InstKind::IntTrunc(r(a), *w),
220
+        InstKind::PtrToInt(a) => InstKind::PtrToInt(r(a)),
221
+        InstKind::IntToPtr(a, ty) => InstKind::IntToPtr(r(a), ty.clone()),
222
+        InstKind::Alloca(t) => InstKind::Alloca(t.clone()),
223
+        InstKind::Load(a) => InstKind::Load(r(a)),
216224
         InstKind::Store(v, p) => InstKind::Store(r(v), r(p)),
217
-        InstKind::GetElementPtr(base, idxs) =>
218
-            InstKind::GetElementPtr(r(base), idxs.iter().map(&r).collect()),
219
-        InstKind::Call(f, args) =>
220
-            InstKind::Call(f.clone(), args.iter().map(&r).collect()),
221
-        InstKind::RuntimeCall(f, args) =>
222
-            InstKind::RuntimeCall(f.clone(), args.iter().map(&r).collect()),
223
-        InstKind::ExtractField(v, idx)     => InstKind::ExtractField(r(v), *idx),
225
+        InstKind::GetElementPtr(base, idxs) => {
226
+            InstKind::GetElementPtr(r(base), idxs.iter().map(&r).collect())
227
+        }
228
+        InstKind::Call(f, args) => InstKind::Call(f.clone(), args.iter().map(&r).collect()),
229
+        InstKind::RuntimeCall(f, args) => {
230
+            InstKind::RuntimeCall(f.clone(), args.iter().map(&r).collect())
231
+        }
232
+        InstKind::ExtractField(v, idx) => InstKind::ExtractField(r(v), *idx),
224233
         InstKind::InsertField(v, idx, fld) => InstKind::InsertField(r(v), *idx, r(fld)),
225234
     }
226235
 }
@@ -237,20 +246,28 @@ pub fn remap_terminator(
237246
     match term {
238247
         Terminator::Return(v) => Terminator::Return(v.map(|x| rv(&x))),
239248
         Terminator::Branch(dest, args) => Terminator::Branch(rb(dest), rvs(args)),
240
-        Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args } =>
241
-            Terminator::CondBranch {
242
-                cond: rv(cond),
243
-                true_dest: rb(true_dest),
244
-                true_args: rvs(true_args),
245
-                false_dest: rb(false_dest),
246
-                false_args: rvs(false_args),
247
-            },
248
-        Terminator::Switch { selector, default, cases } =>
249
-            Terminator::Switch {
250
-                selector: rv(selector),
251
-                default: rb(default),
252
-                cases: cases.iter().map(|(v, d)| (*v, rb(d))).collect(),
253
-            },
249
+        Terminator::CondBranch {
250
+            cond,
251
+            true_dest,
252
+            true_args,
253
+            false_dest,
254
+            false_args,
255
+        } => Terminator::CondBranch {
256
+            cond: rv(cond),
257
+            true_dest: rb(true_dest),
258
+            true_args: rvs(true_args),
259
+            false_dest: rb(false_dest),
260
+            false_args: rvs(false_args),
261
+        },
262
+        Terminator::Switch {
263
+            selector,
264
+            default,
265
+            cases,
266
+        } => Terminator::Switch {
267
+            selector: rv(selector),
268
+            default: rb(default),
269
+            cases: cases.iter().map(|(v, d)| (*v, rb(d))).collect(),
270
+        },
254271
         Terminator::Unreachable => Terminator::Unreachable,
255272
     }
256273
 }
src/opt/lsf.rsmodified
475 lines changed — click to load
@@ -43,8 +43,8 @@
4343
 //! %x = iadd %42, %1
4444
 //! ```
4545
 
46
+use super::alias::{self, may_reach_through_call_arg, AliasResult};
4647
 use super::pass::Pass;
47
-use super::alias::{self, AliasResult, may_reach_through_call_arg};
4848
 use crate::ir::inst::*;
4949
 use crate::ir::types::IrType;
5050
 use crate::ir::walk::{for_each_operand_mut, for_each_terminator_operand_mut};
@@ -53,7 +53,9 @@ use std::collections::HashMap;
5353
 pub struct LocalLsf;
5454
 
5555
 impl Pass for LocalLsf {
56
-    fn name(&self) -> &'static str { "load-store-fwd" }
56
+    fn name(&self) -> &'static str {
57
+        "load-store-fwd"
58
+    }
5759
 
5860
     fn run(&self, module: &mut Module) -> bool {
5961
         let mut changed = false;
@@ -85,13 +87,19 @@ fn lsf_in_function(func: &mut Function) -> bool {
8587
                     available.retain(|entry| {
8688
                         matches!(alias::query(func, entry.ptr, eff_ptr), AliasResult::NoAlias)
8789
                     });
88
-                    available.push(AvailableStore { ptr: eff_ptr, val: eff_val });
90
+                    available.push(AvailableStore {
91
+                        ptr: eff_ptr,
92
+                        val: eff_val,
93
+                    });
8994
                 }
9095
 
9196
                 InstKind::Load(ptr) => {
9297
                     let eff_ptr = resolve(&all_rewrites, *ptr);
9398
                     if let Some(entry) = available.iter().rev().find(|entry| {
94
-                        matches!(alias::query(func, entry.ptr, eff_ptr), AliasResult::MustAlias)
99
+                        matches!(
100
+                            alias::query(func, entry.ptr, eff_ptr),
101
+                            AliasResult::MustAlias
102
+                        )
95103
                     }) {
96104
                         all_rewrites.insert(inst.id, entry.val);
97105
                         changed = true;
@@ -113,9 +121,9 @@ fn lsf_in_function(func: &mut Function) -> bool {
113121
                         // so a precise "different GEP offset →
114122
                         // NoAlias" answer is unsound here.
115123
                         available.retain(|entry| {
116
-                            pointer_args.iter().all(|arg| {
117
-                                !may_reach_through_call_arg(func, entry.ptr, *arg)
118
-                            })
124
+                            pointer_args
125
+                                .iter()
126
+                                .all(|arg| !may_reach_through_call_arg(func, entry.ptr, *arg))
119127
                         });
120128
                     }
121129
                 }
@@ -145,7 +153,9 @@ fn resolve(rewrites: &HashMap<ValueId, ValueId>, mut v: ValueId) -> ValueId {
145153
     while let Some(&next) = rewrites.get(&v) {
146154
         v = next;
147155
         steps += 1;
148
-        if steps > 64 { break; } // cycle guard (SSA has none, but be safe)
156
+        if steps > 64 {
157
+            break;
158
+        } // cycle guard (SSA has none, but be safe)
149159
     }
150160
     v
151161
 }
@@ -175,10 +185,17 @@ fn value_is_pointer(func: &Function, value: ValueId) -> bool {
175185
     if matches!(func.value_type(value), Some(IrType::Ptr(_))) {
176186
         return true;
177187
     }
178
-    if func.params.iter().any(|param| param.id == value && matches!(param.ty, IrType::Ptr(_))) {
188
+    if func
189
+        .params
190
+        .iter()
191
+        .any(|param| param.id == value && matches!(param.ty, IrType::Ptr(_)))
192
+    {
179193
         return true;
180194
     }
181
-    func.blocks.iter().flat_map(|block| block.insts.iter()).find(|inst| inst.id == value)
195
+    func.blocks
196
+        .iter()
197
+        .flat_map(|block| block.insts.iter())
198
+        .find(|inst| inst.id == value)
182199
         .map(|inst| matches!(inst.ty, IrType::Ptr(_)))
183200
         .unwrap_or(false)
184201
 }
@@ -190,19 +207,28 @@ fn value_is_pointer(func: &Function, value: ValueId) -> bool {
190207
 #[cfg(test)]
191208
 mod tests {
192209
     use super::*;
193
-    use crate::ir::types::{IrType, IntWidth};
194
-    use crate::opt::pass::Pass;
210
+    use crate::ir::types::{IntWidth, IrType};
195211
     use crate::lexer::{Position, Span};
212
+    use crate::opt::pass::Pass;
196213
 
197214
     fn dummy_span() -> Span {
198215
         let p = Position { line: 0, col: 0 };
199
-        Span { file_id: 0, start: p, end: p }
216
+        Span {
217
+            file_id: 0,
218
+            start: p,
219
+            end: p,
220
+        }
200221
     }
201222
 
202223
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
203224
         let id = f.next_value_id();
204225
         let entry = f.entry;
205
-        f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
226
+        f.block_mut(entry).insts.push(Inst {
227
+            id,
228
+            kind,
229
+            ty,
230
+            span: dummy_span(),
231
+        });
206232
         id
207233
     }
208234
 
@@ -223,16 +249,29 @@ mod tests {
223249
         let mut m = Module::new("test".into());
224250
         let mut f = Function::new("f".into(), vec![], IrType::Void);
225251
 
226
-        let alloca = push(&mut f, InstKind::Alloca(IrType::Int(IntWidth::I32)),
227
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
228
-        let val42  = push(&mut f, InstKind::ConstInt(42, IntWidth::I32),
229
-                          IrType::Int(IntWidth::I32));
230
-        let one    = push(&mut f, InstKind::ConstInt(1, IntWidth::I32),
231
-                          IrType::Int(IntWidth::I32));
252
+        let alloca = push(
253
+            &mut f,
254
+            InstKind::Alloca(IrType::Int(IntWidth::I32)),
255
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
256
+        );
257
+        let val42 = push(
258
+            &mut f,
259
+            InstKind::ConstInt(42, IntWidth::I32),
260
+            IrType::Int(IntWidth::I32),
261
+        );
262
+        let one = push(
263
+            &mut f,
264
+            InstKind::ConstInt(1, IntWidth::I32),
265
+            IrType::Int(IntWidth::I32),
266
+        );
232267
         push(&mut f, InstKind::Store(val42, alloca), IrType::Void);
233
-        let load   = push(&mut f, InstKind::Load(alloca), IrType::Int(IntWidth::I32));
234
-        let add    = push(&mut f, InstKind::IAdd(load, one), IrType::Int(IntWidth::I32));
235
-        let entry  = f.entry;
268
+        let load = push(&mut f, InstKind::Load(alloca), IrType::Int(IntWidth::I32));
269
+        let add = push(
270
+            &mut f,
271
+            InstKind::IAdd(load, one),
272
+            IrType::Int(IntWidth::I32),
273
+        );
274
+        let entry = f.entry;
236275
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(add)));
237276
         m.add_function(f);
238277
 
@@ -246,7 +285,8 @@ mod tests {
246285
         let add_inst = insts.iter().find(|i| i.id == add).unwrap();
247286
         assert!(
248287
             matches!(&add_inst.kind, InstKind::IAdd(a, _) if *a == val42),
249
-            "IAdd operand should be forwarded to val42, got {:?}", add_inst.kind
288
+            "IAdd operand should be forwarded to val42, got {:?}",
289
+            add_inst.kind
250290
         );
251291
     }
252292
 
@@ -258,12 +298,21 @@ mod tests {
258298
         let mut m = Module::new("test".into());
259299
         let mut f = Function::new("f".into(), vec![], IrType::Void);
260300
 
261
-        let alloca = push(&mut f, InstKind::Alloca(IrType::Int(IntWidth::I32)),
262
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
263
-        let v42 = push(&mut f, InstKind::ConstInt(42, IntWidth::I32),
264
-                       IrType::Int(IntWidth::I32));
265
-        let v99 = push(&mut f, InstKind::ConstInt(99, IntWidth::I32),
266
-                       IrType::Int(IntWidth::I32));
301
+        let alloca = push(
302
+            &mut f,
303
+            InstKind::Alloca(IrType::Int(IntWidth::I32)),
304
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
305
+        );
306
+        let v42 = push(
307
+            &mut f,
308
+            InstKind::ConstInt(42, IntWidth::I32),
309
+            IrType::Int(IntWidth::I32),
310
+        );
311
+        let v99 = push(
312
+            &mut f,
313
+            InstKind::ConstInt(99, IntWidth::I32),
314
+            IrType::Int(IntWidth::I32),
315
+        );
267316
         push(&mut f, InstKind::Store(v42, alloca), IrType::Void);
268317
         push(&mut f, InstKind::Store(v99, alloca), IrType::Void);
269318
         let load = push(&mut f, InstKind::Load(alloca), IrType::Int(IntWidth::I32));
@@ -279,7 +328,8 @@ mod tests {
279328
         let term = func.block(func.entry).terminator.as_ref().unwrap();
280329
         assert!(
281330
             matches!(term, Terminator::Return(Some(v)) if *v == v99),
282
-            "Return should use v99 (the latest store), got {:?}", term
331
+            "Return should use v99 (the latest store), got {:?}",
332
+            term
283333
         );
284334
     }
285335
 
@@ -291,15 +341,23 @@ mod tests {
291341
         let mut m = Module::new("test".into());
292342
         let mut f = Function::new("f".into(), vec![], IrType::Void);
293343
 
294
-        let alloca = push(&mut f, InstKind::Alloca(IrType::Int(IntWidth::I32)),
295
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
296
-        let v42 = push(&mut f, InstKind::ConstInt(42, IntWidth::I32),
297
-                       IrType::Int(IntWidth::I32));
344
+        let alloca = push(
345
+            &mut f,
346
+            InstKind::Alloca(IrType::Int(IntWidth::I32)),
347
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
348
+        );
349
+        let v42 = push(
350
+            &mut f,
351
+            InstKind::ConstInt(42, IntWidth::I32),
352
+            IrType::Int(IntWidth::I32),
353
+        );
298354
         push(&mut f, InstKind::Store(v42, alloca), IrType::Void);
299355
         // A call that might write to the alloca.
300
-        push(&mut f, InstKind::Call(
301
-            FuncRef::External("ext".into()), vec![alloca]
302
-        ), IrType::Void);
356
+        push(
357
+            &mut f,
358
+            InstKind::Call(FuncRef::External("ext".into()), vec![alloca]),
359
+            IrType::Void,
360
+        );
303361
         let load = push(&mut f, InstKind::Load(alloca), IrType::Int(IntWidth::I32));
304362
         let entry = f.entry;
305363
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(load)));
@@ -317,8 +375,11 @@ mod tests {
317375
         let mut m = Module::new("test".into());
318376
         let mut f = Function::new("f".into(), vec![], IrType::Void);
319377
 
320
-        let alloca = push(&mut f, InstKind::Alloca(IrType::Int(IntWidth::I32)),
321
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
378
+        let alloca = push(
379
+            &mut f,
380
+            InstKind::Alloca(IrType::Int(IntWidth::I32)),
381
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
382
+        );
322383
         let load = push(&mut f, InstKind::Load(alloca), IrType::Int(IntWidth::I32));
323384
         let entry = f.entry;
324385
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(load)));
@@ -337,8 +398,16 @@ mod tests {
337398
         let arr_ty = IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 4);
338399
         let arr_ptr_ty = IrType::Ptr(Box::new(arr_ty.clone()));
339400
         let ptr = push(&mut f, InstKind::Alloca(arr_ty), arr_ptr_ty);
340
-        let zero0 = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
341
-        let zero1 = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
401
+        let zero0 = push(
402
+            &mut f,
403
+            InstKind::ConstInt(0, IntWidth::I32),
404
+            IrType::Int(IntWidth::I32),
405
+        );
406
+        let zero1 = push(
407
+            &mut f,
408
+            InstKind::ConstInt(0, IntWidth::I32),
409
+            IrType::Int(IntWidth::I32),
410
+        );
342411
         let gep0 = push(
343412
             &mut f,
344413
             InstKind::GetElementPtr(ptr, vec![zero0]),
@@ -349,15 +418,26 @@ mod tests {
349418
             InstKind::GetElementPtr(ptr, vec![zero1]),
350419
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))),
351420
         );
352
-        let v42 = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
421
+        let v42 = push(
422
+            &mut f,
423
+            InstKind::ConstInt(42, IntWidth::I32),
424
+            IrType::Int(IntWidth::I32),
425
+        );
353426
         push(&mut f, InstKind::Store(v42, gep0), IrType::Void);
354427
         let load = push(&mut f, InstKind::Load(gep1), IrType::Int(IntWidth::I32));
355428
         let entry = f.entry;
356429
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(load)));
357430
         m.add_function(f);
358431
 
359
-        assert!(LocalLsf.run(&mut m), "LSF should forward across must-alias GEPs");
360
-        let term = m.functions[0].block(m.functions[0].entry).terminator.as_ref().unwrap();
432
+        assert!(
433
+            LocalLsf.run(&mut m),
434
+            "LSF should forward across must-alias GEPs"
435
+        );
436
+        let term = m.functions[0]
437
+            .block(m.functions[0].entry)
438
+            .terminator
439
+            .as_ref()
440
+            .unwrap();
361441
         assert!(
362442
             matches!(term, Terminator::Return(Some(v)) if *v == v42),
363443
             "return should use the stored value after forwarding, got {:?}",
@@ -378,24 +458,53 @@ mod tests {
378458
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
379459
 
380460
         let arr_ty = IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 2);
381
-        let alloca = push(&mut f, InstKind::Alloca(arr_ty.clone()),
382
-                          IrType::Ptr(Box::new(arr_ty)));
383
-        let c0 = push(&mut f, InstKind::ConstInt(0, IntWidth::I64), IrType::Int(IntWidth::I64));
384
-        let c1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I64), IrType::Int(IntWidth::I64));
385
-        let g0 = push(&mut f, InstKind::GetElementPtr(alloca, vec![c0]),
386
-                      IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
387
-        let g1 = push(&mut f, InstKind::GetElementPtr(alloca, vec![c1]),
388
-                      IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
389
-        let v20 = push(&mut f, InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32));
461
+        let alloca = push(
462
+            &mut f,
463
+            InstKind::Alloca(arr_ty.clone()),
464
+            IrType::Ptr(Box::new(arr_ty)),
465
+        );
466
+        let c0 = push(
467
+            &mut f,
468
+            InstKind::ConstInt(0, IntWidth::I64),
469
+            IrType::Int(IntWidth::I64),
470
+        );
471
+        let c1 = push(
472
+            &mut f,
473
+            InstKind::ConstInt(1, IntWidth::I64),
474
+            IrType::Int(IntWidth::I64),
475
+        );
476
+        let g0 = push(
477
+            &mut f,
478
+            InstKind::GetElementPtr(alloca, vec![c0]),
479
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
480
+        );
481
+        let g1 = push(
482
+            &mut f,
483
+            InstKind::GetElementPtr(alloca, vec![c1]),
484
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
485
+        );
486
+        let v20 = push(
487
+            &mut f,
488
+            InstKind::ConstInt(20, IntWidth::I32),
489
+            IrType::Int(IntWidth::I32),
490
+        );
390491
         push(&mut f, InstKind::Store(v20, g1), IrType::Void);
391
-        push(&mut f, InstKind::Call(FuncRef::External("touch".into()), vec![g0]), IrType::Void);
492
+        push(
493
+            &mut f,
494
+            InstKind::Call(FuncRef::External("touch".into()), vec![g0]),
495
+            IrType::Void,
496
+        );
392497
         let load = push(&mut f, InstKind::Load(g1), IrType::Int(IntWidth::I32));
393498
         let entry = f.entry;
394499
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(load)));
395500
         m.add_function(f);
396501
 
397502
         LocalLsf.run(&mut m);
398
-        let term = m.functions[0].block(m.functions[0].entry).terminator.as_ref().unwrap();
503
+        let term = m.functions[0]
504
+            .block(m.functions[0].entry)
505
+            .terminator
506
+            .as_ref()
507
+            .unwrap();
399508
         if let Terminator::Return(Some(v)) = term {
400509
             assert_ne!(*v, v20, "LSF forwarded arr[1] load to the caller's pre-call constant across a call that received arr[0]; callee could have walked to arr[1]");
401510
         } else {
@@ -425,26 +534,61 @@ mod tests {
425534
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
426535
 
427536
         let arr_ty = IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 2);
428
-        let alloca = push(&mut f, InstKind::Alloca(arr_ty.clone()),
429
-                          IrType::Ptr(Box::new(arr_ty)));
430
-        let c0 = push(&mut f, InstKind::ConstInt(0, IntWidth::I64), IrType::Int(IntWidth::I64));
431
-        let c1 = push(&mut f, InstKind::ConstInt(1, IntWidth::I64), IrType::Int(IntWidth::I64));
432
-        let g0 = push(&mut f, InstKind::GetElementPtr(alloca, vec![c0]),
433
-                      IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
434
-        let g1 = push(&mut f, InstKind::GetElementPtr(alloca, vec![c1]),
435
-                      IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
436
-
437
-        let v20 = push(&mut f, InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32));
537
+        let alloca = push(
538
+            &mut f,
539
+            InstKind::Alloca(arr_ty.clone()),
540
+            IrType::Ptr(Box::new(arr_ty)),
541
+        );
542
+        let c0 = push(
543
+            &mut f,
544
+            InstKind::ConstInt(0, IntWidth::I64),
545
+            IrType::Int(IntWidth::I64),
546
+        );
547
+        let c1 = push(
548
+            &mut f,
549
+            InstKind::ConstInt(1, IntWidth::I64),
550
+            IrType::Int(IntWidth::I64),
551
+        );
552
+        let g0 = push(
553
+            &mut f,
554
+            InstKind::GetElementPtr(alloca, vec![c0]),
555
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
556
+        );
557
+        let g1 = push(
558
+            &mut f,
559
+            InstKind::GetElementPtr(alloca, vec![c1]),
560
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
561
+        );
562
+
563
+        let v20 = push(
564
+            &mut f,
565
+            InstKind::ConstInt(20, IntWidth::I32),
566
+            IrType::Int(IntWidth::I32),
567
+        );
438568
         push(&mut f, InstKind::Store(v20, g1), IrType::Void);
439569
 
440
-        let chain0 = push(&mut f, InstKind::GetElementPtr(g0, vec![c0]),
441
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
442
-        let v11 = push(&mut f, InstKind::ConstInt(11, IntWidth::I32), IrType::Int(IntWidth::I32));
570
+        let chain0 = push(
571
+            &mut f,
572
+            InstKind::GetElementPtr(g0, vec![c0]),
573
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
574
+        );
575
+        let v11 = push(
576
+            &mut f,
577
+            InstKind::ConstInt(11, IntWidth::I32),
578
+            IrType::Int(IntWidth::I32),
579
+        );
443580
         push(&mut f, InstKind::Store(v11, chain0), IrType::Void);
444581
 
445
-        let chain1 = push(&mut f, InstKind::GetElementPtr(g0, vec![c1]),
446
-                          IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
447
-        let v31 = push(&mut f, InstKind::ConstInt(31, IntWidth::I32), IrType::Int(IntWidth::I32));
582
+        let chain1 = push(
583
+            &mut f,
584
+            InstKind::GetElementPtr(g0, vec![c1]),
585
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
586
+        );
587
+        let v31 = push(
588
+            &mut f,
589
+            InstKind::ConstInt(31, IntWidth::I32),
590
+            IrType::Int(IntWidth::I32),
591
+        );
448592
         push(&mut f, InstKind::Store(v31, chain1), IrType::Void);
449593
 
450594
         let load = push(&mut f, InstKind::Load(g1), IrType::Int(IntWidth::I32));
@@ -453,7 +597,11 @@ mod tests {
453597
         m.add_function(f);
454598
 
455599
         LocalLsf.run(&mut m);
456
-        let term = m.functions[0].block(m.functions[0].entry).terminator.as_ref().unwrap();
600
+        let term = m.functions[0]
601
+            .block(m.functions[0].entry)
602
+            .terminator
603
+            .as_ref()
604
+            .unwrap();
457605
         // The load must either remain or be forwarded to v31 — never
458606
         // to v20.
459607
         if let Terminator::Return(Some(v)) = term {
@@ -472,14 +620,22 @@ mod tests {
472620
             IrType::Int(IntWidth::I32),
473621
         );
474622
 
475
-        let v42 = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
623
+        let v42 = push(
624
+            &mut f,
625
+            InstKind::ConstInt(42, IntWidth::I32),
626
+            IrType::Int(IntWidth::I32),
627
+        );
476628
         push(&mut f, InstKind::Store(v42, ValueId(0)), IrType::Void);
477629
         push(
478630
             &mut f,
479631
             InstKind::Call(FuncRef::External("touch".into()), vec![ValueId(1)]),
480632
             IrType::Void,
481633
         );
482
-        let load = push(&mut f, InstKind::Load(ValueId(0)), IrType::Int(IntWidth::I32));
634
+        let load = push(
635
+            &mut f,
636
+            InstKind::Load(ValueId(0)),
637
+            IrType::Int(IntWidth::I32),
638
+        );
483639
         let entry = f.entry;
484640
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(load)));
485641
         m.add_function(f);
@@ -488,7 +644,11 @@ mod tests {
488644
             LocalLsf.run(&mut m),
489645
             "LSF should preserve the stored value across a noalias pointer call"
490646
         );
491
-        let term = m.functions[0].block(m.functions[0].entry).terminator.as_ref().unwrap();
647
+        let term = m.functions[0]
648
+            .block(m.functions[0].entry)
649
+            .terminator
650
+            .as_ref()
651
+            .unwrap();
492652
         assert!(
493653
             matches!(term, Terminator::Return(Some(v)) if *v == v42),
494654
             "return should use the forwarded value across the noalias call, got {:?}",
src/opt/mem2reg.rsmodified
1711 lines changed — click to load
@@ -62,11 +62,8 @@
6262
 
6363
 use super::pass::Pass;
6464
 use super::util::{
65
-    compute_dominance_frontiers,
66
-    compute_immediate_dominators,
67
-    dominator_tree_children,
68
-    prune_unreachable,
69
-    substitute_uses,
65
+    compute_dominance_frontiers, compute_immediate_dominators, dominator_tree_children,
66
+    prune_unreachable, substitute_uses,
7067
 };
7168
 use crate::ir::inst::*;
7269
 use crate::ir::types::IrType;
@@ -76,7 +73,9 @@ use std::collections::{HashMap, HashSet, VecDeque};
7673
 pub struct Mem2Reg;
7774
 
7875
 impl Pass for Mem2Reg {
79
-    fn name(&self) -> &'static str { "mem2reg" }
76
+    fn name(&self) -> &'static str {
77
+        "mem2reg"
78
+    }
8079
 
8180
     fn run(&self, module: &mut Module) -> bool {
8281
         let mut changed = false;
@@ -122,11 +121,14 @@ fn promote_function(func: &mut Function) -> bool {
122121
 
123122
     // ---- Phase 1: find promotable allocas -------------------------
124123
     let promotable = find_promotable_allocas(func);
125
-    if promotable.is_empty() { return pruned; }
124
+    if promotable.is_empty() {
125
+        return pruned;
126
+    }
126127
 
127128
     // Map from alloca ValueId → index into `promotable`. We use the
128129
     // index as a compact key throughout the rest of the pass.
129
-    let alloca_index: HashMap<ValueId, usize> = promotable.iter()
130
+    let alloca_index: HashMap<ValueId, usize> = promotable
131
+        .iter()
130132
         .enumerate()
131133
         .map(|(i, p)| (p.alloca_id, i))
132134
         .collect();
@@ -188,7 +190,10 @@ fn promote_function(func: &mut Function) -> bool {
188190
     let mut undef_values: Vec<ValueId> = Vec::with_capacity(promotable.len());
189191
 
190192
     // Grab a dummy span we can reuse for inserted insts.
191
-    let span = func.block(func.entry).insts.first()
193
+    let span = func
194
+        .block(func.entry)
195
+        .insts
196
+        .first()
192197
         .map(|i| i.span)
193198
         .or_else(|| {
194199
             func.block(func.entry).terminator.as_ref().map(|_t| {
@@ -196,14 +201,14 @@ fn promote_function(func: &mut Function) -> bool {
196201
                 // zero span — good enough for synthesized insts.
197202
                 crate::lexer::Span {
198203
                     start: crate::lexer::Position { line: 0, col: 0 },
199
-                    end:   crate::lexer::Position { line: 0, col: 0 },
204
+                    end: crate::lexer::Position { line: 0, col: 0 },
200205
                     file_id: 0,
201206
                 }
202207
             })
203208
         })
204209
         .unwrap_or(crate::lexer::Span {
205210
             start: crate::lexer::Position { line: 0, col: 0 },
206
-            end:   crate::lexer::Position { line: 0, col: 0 },
211
+            end: crate::lexer::Position { line: 0, col: 0 },
207212
             file_id: 0,
208213
         });
209214
 
@@ -223,12 +228,15 @@ fn promote_function(func: &mut Function) -> bool {
223228
         new_undefs.push((id, p.pointee_ty.clone()));
224229
     }
225230
     for (id, ty) in new_undefs.iter().rev() {
226
-        func.block_mut(entry).insts.insert(0, Inst {
227
-            id: *id,
228
-            kind: InstKind::Undef(ty.clone()),
229
-            ty: ty.clone(),
230
-            span,
231
-        });
231
+        func.block_mut(entry).insts.insert(
232
+            0,
233
+            Inst {
234
+                id: *id,
235
+                kind: InstKind::Undef(ty.clone()),
236
+                ty: ty.clone(),
237
+                span,
238
+            },
239
+        );
232240
     }
233241
 
234242
     // Now insert block params. Order within a block matters: we
@@ -301,9 +309,7 @@ fn promote_function(func: &mut Function) -> bool {
301309
     // Current value stack per alloca. Initialized with the entry
302310
     // Undef for each alloca so that any Load before any Store on
303311
     // this dom-tree path sees undef.
304
-    let mut stacks: Vec<Vec<ValueId>> = undef_values.iter()
305
-        .map(|&u| vec![u])
306
-        .collect();
312
+    let mut stacks: Vec<Vec<ValueId>> = undef_values.iter().map(|&u| vec![u]).collect();
307313
 
308314
     // (old_load_id, new_value_id) rewrites to apply at the end.
309315
     let mut load_renames: HashMap<ValueId, ValueId> = HashMap::new();
@@ -395,7 +401,11 @@ fn promote_function(func: &mut Function) -> bool {
395401
             let raw: Vec<BlockId> = match &block.terminator {
396402
                 Some(Terminator::Return(_)) | Some(Terminator::Unreachable) | None => vec![],
397403
                 Some(Terminator::Branch(d, _)) => vec![*d],
398
-                Some(Terminator::CondBranch { true_dest, false_dest, .. }) => {
404
+                Some(Terminator::CondBranch {
405
+                    true_dest,
406
+                    false_dest,
407
+                    ..
408
+                }) => {
399409
                     vec![*true_dest, *false_dest]
400410
                 }
401411
                 Some(Terminator::Switch { cases, default, .. }) => {
@@ -413,11 +423,14 @@ fn promote_function(func: &mut Function) -> bool {
413423
                 // current stack top as a branch arg. The order
414424
                 // matches the order the params were pushed onto
415425
                 // `succ.params` during phase 3.
416
-                let new_args: Vec<ValueId> = order.iter()
417
-                    .map(|&idx| resolve_promoted_value(
418
-                        *stacks[idx].last().expect("mem2reg: stack empty at branch"),
419
-                        load_renames,
420
-                    ))
426
+                let new_args: Vec<ValueId> = order
427
+                    .iter()
428
+                    .map(|&idx| {
429
+                        resolve_promoted_value(
430
+                            *stacks[idx].last().expect("mem2reg: stack empty at branch"),
431
+                            load_renames,
432
+                        )
433
+                    })
421434
                     .collect();
422435
                 // Locate the slots in the terminator's arg list.
423436
                 let block_mut = func.block_mut(block_id);
@@ -431,9 +444,17 @@ fn promote_function(func: &mut Function) -> bool {
431444
         let kids: Vec<BlockId> = children.get(&block_id).cloned().unwrap_or_default();
432445
         for kid in kids {
433446
             rename_block(
434
-                func, kid, promotable, alloca_index, phi_params,
435
-                block_phi_order, children, stacks,
436
-                load_renames, dead_loads, dead_stores,
447
+                func,
448
+                kid,
449
+                promotable,
450
+                alloca_index,
451
+                phi_params,
452
+                block_phi_order,
453
+                children,
454
+                stacks,
455
+                load_renames,
456
+                dead_loads,
457
+                dead_stores,
437458
             );
438459
         }
439460
 
@@ -446,9 +467,17 @@ fn promote_function(func: &mut Function) -> bool {
446467
     }
447468
 
448469
     rename_block(
449
-        func, func.entry, &promotable, &alloca_index, &phi_params,
450
-        &block_phi_order, &children, &mut stacks,
451
-        &mut load_renames, &mut dead_loads, &mut dead_stores,
470
+        func,
471
+        func.entry,
472
+        &promotable,
473
+        &alloca_index,
474
+        &phi_params,
475
+        &block_phi_order,
476
+        &children,
477
+        &mut stacks,
478
+        &mut load_renames,
479
+        &mut dead_loads,
480
+        &mut dead_stores,
452481
     );
453482
 
454483
     // ---- Phase 5: apply load renames and delete dead insts --------
@@ -460,9 +489,15 @@ fn promote_function(func: &mut Function) -> bool {
460489
     let alloca_ids: HashSet<ValueId> = promotable.iter().map(|p| p.alloca_id).collect();
461490
     for block in &mut func.blocks {
462491
         block.insts.retain(|inst| {
463
-            if dead_loads.contains(&inst.id) { return false; }
464
-            if dead_stores.contains(&inst.id) { return false; }
465
-            if alloca_ids.contains(&inst.id) { return false; }
492
+            if dead_loads.contains(&inst.id) {
493
+                return false;
494
+            }
495
+            if dead_stores.contains(&inst.id) {
496
+                return false;
497
+            }
498
+            if alloca_ids.contains(&inst.id) {
499
+                return false;
500
+            }
466501
             true
467502
         });
468503
     }
@@ -470,10 +505,7 @@ fn promote_function(func: &mut Function) -> bool {
470505
     true
471506
 }
472507
 
473
-fn resolve_promoted_value(
474
-    mut value: ValueId,
475
-    load_renames: &HashMap<ValueId, ValueId>,
476
-) -> ValueId {
508
+fn resolve_promoted_value(mut value: ValueId, load_renames: &HashMap<ValueId, ValueId>) -> ValueId {
477509
     let mut seen = HashSet::new();
478510
     while let Some(&next) = load_renames.get(&value) {
479511
         if !seen.insert(value) || next == value {
@@ -500,7 +532,9 @@ fn find_promotable_allocas(func: &Function) -> Vec<Promotable> {
500532
             }
501533
         }
502534
     }
503
-    if candidates.is_empty() { return Vec::new(); }
535
+    if candidates.is_empty() {
536
+        return Vec::new();
537
+    }
504538
 
505539
     // Second pass: walk every use and disqualify any alloca whose
506540
     // ValueId appears in a non-load/non-store-addr position.
@@ -557,7 +591,10 @@ fn find_promotable_allocas(func: &Function) -> Vec<Promotable> {
557591
         for inst in &block.insts {
558592
             if let InstKind::Alloca(_) = &inst.kind {
559593
                 if let Some(ty) = candidates.remove(&inst.id) {
560
-                    out.push(Promotable { alloca_id: inst.id, pointee_ty: ty });
594
+                    out.push(Promotable {
595
+                        alloca_id: inst.id,
596
+                        pointee_ty: ty,
597
+                    });
561598
                 }
562599
             }
563600
         }
@@ -581,7 +618,13 @@ fn append_branch_args_for(term: &mut Terminator, target: BlockId, new_args: &[Va
581618
         Terminator::Branch(d, args) if *d == target => {
582619
             args.extend_from_slice(new_args);
583620
         }
584
-        Terminator::CondBranch { true_dest, true_args, false_dest, false_args, .. } => {
621
+        Terminator::CondBranch {
622
+            true_dest,
623
+            true_args,
624
+            false_dest,
625
+            false_args,
626
+            ..
627
+        } => {
585628
             if *true_dest == target {
586629
                 true_args.extend_from_slice(new_args);
587630
             }
@@ -600,16 +643,25 @@ mod tests {
600643
     use super::*;
601644
     use crate::ir::types::IntWidth;
602645
     use crate::ir::verify::verify_module;
603
-    use crate::lexer::{Span, Position};
646
+    use crate::lexer::{Position, Span};
604647
 
605648
     fn dummy_span() -> Span {
606649
         let p = Position { line: 1, col: 1 };
607
-        Span { start: p, end: p, file_id: 0 }
650
+        Span {
651
+            start: p,
652
+            end: p,
653
+            file_id: 0,
654
+        }
608655
     }
609656
 
610657
     fn push_inst(f: &mut Function, block: BlockId, kind: InstKind, ty: IrType) -> ValueId {
611658
         let id = f.next_value_id();
612
-        f.block_mut(block).insts.push(Inst { id, kind, ty, span: dummy_span() });
659
+        f.block_mut(block).insts.push(Inst {
660
+            id,
661
+            kind,
662
+            ty,
663
+            span: dummy_span(),
664
+        });
613665
         id
614666
     }
615667
 
@@ -623,19 +675,22 @@ mod tests {
623675
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
624676
         let entry = f.entry;
625677
 
626
-        let slot = push_inst(&mut f, entry,
678
+        let slot = push_inst(
679
+            &mut f,
680
+            entry,
627681
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
628682
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
629683
         );
630
-        let c7 = push_inst(&mut f, entry,
684
+        let c7 = push_inst(
685
+            &mut f,
686
+            entry,
631687
             InstKind::ConstInt(7, IntWidth::I32),
632688
             IrType::Int(IntWidth::I32),
633689
         );
634
-        push_inst(&mut f, entry,
635
-            InstKind::Store(c7, slot),
636
-            IrType::Void,
637
-        );
638
-        let loaded = push_inst(&mut f, entry,
690
+        push_inst(&mut f, entry, InstKind::Store(c7, slot), IrType::Void);
691
+        let loaded = push_inst(
692
+            &mut f,
693
+            entry,
639694
             InstKind::Load(slot),
640695
             IrType::Int(IntWidth::I32),
641696
         );
@@ -649,15 +704,31 @@ mod tests {
649704
         // After: alloca/store/load all gone. The return should
650705
         // reference c7 directly (via substitution).
651706
         let block = &m.functions[0].blocks[0];
652
-        assert!(!block.insts.iter().any(|i| matches!(i.kind, InstKind::Alloca(_))),
653
-            "alloca should be gone");
654
-        assert!(!block.insts.iter().any(|i| matches!(i.kind, InstKind::Load(_))),
655
-            "load should be gone");
656
-        assert!(!block.insts.iter().any(|i| matches!(i.kind, InstKind::Store(..))),
657
-            "store should be gone");
707
+        assert!(
708
+            !block
709
+                .insts
710
+                .iter()
711
+                .any(|i| matches!(i.kind, InstKind::Alloca(_))),
712
+            "alloca should be gone"
713
+        );
714
+        assert!(
715
+            !block
716
+                .insts
717
+                .iter()
718
+                .any(|i| matches!(i.kind, InstKind::Load(_))),
719
+            "load should be gone"
720
+        );
721
+        assert!(
722
+            !block
723
+                .insts
724
+                .iter()
725
+                .any(|i| matches!(i.kind, InstKind::Store(..))),
726
+            "store should be gone"
727
+        );
658728
         match block.terminator.as_ref().unwrap() {
659
-            Terminator::Return(Some(v)) => assert_eq!(*v, c7,
660
-                "return should reference the stored const directly"),
729
+            Terminator::Return(Some(v)) => {
730
+                assert_eq!(*v, c7, "return should reference the stored const directly")
731
+            }
661732
             _ => panic!(),
662733
         }
663734
     }
@@ -672,41 +743,45 @@ mod tests {
672743
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
673744
         let entry = f.entry;
674745
 
675
-        let slot = push_inst(&mut f, entry,
746
+        let slot = push_inst(
747
+            &mut f,
748
+            entry,
676749
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
677750
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
678751
         );
679
-        let cond = push_inst(&mut f, entry,
680
-            InstKind::ConstBool(true),
681
-            IrType::Bool,
682
-        );
752
+        let cond = push_inst(&mut f, entry, InstKind::ConstBool(true), IrType::Bool);
683753
         let then_b = f.create_block("then");
684754
         let else_b = f.create_block("else");
685755
         let merge = f.create_block("merge");
686756
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
687
-            cond, true_dest: then_b, true_args: vec![],
688
-            false_dest: else_b, false_args: vec![],
757
+            cond,
758
+            true_dest: then_b,
759
+            true_args: vec![],
760
+            false_dest: else_b,
761
+            false_args: vec![],
689762
         });
690763
 
691
-        let c1 = push_inst(&mut f, then_b,
764
+        let c1 = push_inst(
765
+            &mut f,
766
+            then_b,
692767
             InstKind::ConstInt(1, IntWidth::I32),
693768
             IrType::Int(IntWidth::I32),
694769
         );
695
-        push_inst(&mut f, then_b,
696
-            InstKind::Store(c1, slot), IrType::Void,
697
-        );
770
+        push_inst(&mut f, then_b, InstKind::Store(c1, slot), IrType::Void);
698771
         f.block_mut(then_b).terminator = Some(Terminator::Branch(merge, vec![]));
699772
 
700
-        let c2 = push_inst(&mut f, else_b,
773
+        let c2 = push_inst(
774
+            &mut f,
775
+            else_b,
701776
             InstKind::ConstInt(2, IntWidth::I32),
702777
             IrType::Int(IntWidth::I32),
703778
         );
704
-        push_inst(&mut f, else_b,
705
-            InstKind::Store(c2, slot), IrType::Void,
706
-        );
779
+        push_inst(&mut f, else_b, InstKind::Store(c2, slot), IrType::Void);
707780
         f.block_mut(else_b).terminator = Some(Terminator::Branch(merge, vec![]));
708781
 
709
-        let loaded = push_inst(&mut f, merge,
782
+        let loaded = push_inst(
783
+            &mut f,
784
+            merge,
710785
             InstKind::Load(slot),
711786
             IrType::Int(IntWidth::I32),
712787
         );
@@ -723,11 +798,17 @@ mod tests {
723798
         // that param.
724799
         let f = &m.functions[0];
725800
         let merge_block = f.block(merge);
726
-        assert_eq!(merge_block.params.len(), 1, "merge should have 1 block param");
801
+        assert_eq!(
802
+            merge_block.params.len(),
803
+            1,
804
+            "merge should have 1 block param"
805
+        );
727806
         let param_id = merge_block.params[0].id;
728807
         match merge_block.terminator.as_ref().unwrap() {
729
-            Terminator::Return(Some(v)) => assert_eq!(*v, param_id,
730
-                "return should reference the merge block param"),
808
+            Terminator::Return(Some(v)) => assert_eq!(
809
+                *v, param_id,
810
+                "return should reference the merge block param"
811
+            ),
731812
             _ => panic!(),
732813
         }
733814
 
@@ -760,21 +841,30 @@ mod tests {
760841
         let mut m = Module::new("t".into());
761842
         let mut f = Function::new("f".into(), vec![], IrType::Void);
762843
         let entry = f.entry;
763
-        let slot = push_inst(&mut f, entry,
844
+        let slot = push_inst(
845
+            &mut f,
846
+            entry,
764847
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
765848
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
766849
         );
767850
         // Call that takes the slot's address — escape!
768
-        push_inst(&mut f, entry,
851
+        push_inst(
852
+            &mut f,
853
+            entry,
769854
             InstKind::Call(FuncRef::External("takes_ptr".into()), vec![slot]),
770855
             IrType::Void,
771856
         );
772857
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
773858
         m.add_function(f);
774859
 
775
-        assert!(!Mem2Reg.run(&mut m), "escaping alloca should not be promoted");
860
+        assert!(
861
+            !Mem2Reg.run(&mut m),
862
+            "escaping alloca should not be promoted"
863
+        );
776864
         // The alloca is still there.
777
-        assert!(m.functions[0].blocks[0].insts.iter()
865
+        assert!(m.functions[0].blocks[0]
866
+            .insts
867
+            .iter()
778868
             .any(|i| matches!(i.kind, InstKind::Alloca(_))));
779869
     }
780870
 
@@ -787,28 +877,37 @@ mod tests {
787877
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
788878
         let entry = f.entry;
789879
         // Promotable: only used by store + load.
790
-        let good = push_inst(&mut f, entry,
880
+        let good = push_inst(
881
+            &mut f,
882
+            entry,
791883
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
792884
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
793885
         );
794886
         // Non-promotable: escapes via call.
795
-        let bad = push_inst(&mut f, entry,
887
+        let bad = push_inst(
888
+            &mut f,
889
+            entry,
796890
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
797891
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
798892
         );
799
-        let c42 = push_inst(&mut f, entry,
893
+        let c42 = push_inst(
894
+            &mut f,
895
+            entry,
800896
             InstKind::ConstInt(42, IntWidth::I32),
801897
             IrType::Int(IntWidth::I32),
802898
         );
803
-        push_inst(&mut f, entry,
804
-            InstKind::Store(c42, good), IrType::Void,
805
-        );
806
-        push_inst(&mut f, entry,
899
+        push_inst(&mut f, entry, InstKind::Store(c42, good), IrType::Void);
900
+        push_inst(
901
+            &mut f,
902
+            entry,
807903
             InstKind::Call(FuncRef::External("takes_ptr".into()), vec![bad]),
808904
             IrType::Void,
809905
         );
810
-        let loaded = push_inst(&mut f, entry,
811
-            InstKind::Load(good), IrType::Int(IntWidth::I32),
906
+        let loaded = push_inst(
907
+            &mut f,
908
+            entry,
909
+            InstKind::Load(good),
910
+            IrType::Int(IntWidth::I32),
812911
         );
813912
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(loaded)));
814913
         m.add_function(f);
@@ -819,7 +918,9 @@ mod tests {
819918
 
820919
         let block = &m.functions[0].blocks[0];
821920
         // `good` is gone; `bad` remains.
822
-        let alloca_count = block.insts.iter()
921
+        let alloca_count = block
922
+            .insts
923
+            .iter()
823924
             .filter(|i| matches!(i.kind, InstKind::Alloca(_)))
824925
             .count();
825926
         assert_eq!(alloca_count, 1, "bad alloca should survive");
@@ -840,17 +941,19 @@ mod tests {
840941
         let mut m = Module::new("t".into());
841942
         let mut f = Function::new("f".into(), vec![], IrType::Void);
842943
         let entry = f.entry;
843
-        let slot = push_inst(&mut f, entry,
944
+        let slot = push_inst(
945
+            &mut f,
946
+            entry,
844947
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
845948
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
846949
         );
847
-        let c0 = push_inst(&mut f, entry,
950
+        let c0 = push_inst(
951
+            &mut f,
952
+            entry,
848953
             InstKind::ConstInt(0, IntWidth::I32),
849954
             IrType::Int(IntWidth::I32),
850955
         );
851
-        push_inst(&mut f, entry,
852
-            InstKind::Store(c0, slot), IrType::Void,
853
-        );
956
+        push_inst(&mut f, entry, InstKind::Store(c0, slot), IrType::Void);
854957
 
855958
         let header = f.create_block("header");
856959
         let body = f.create_block("body");
@@ -858,37 +961,52 @@ mod tests {
858961
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![]));
859962
 
860963
         // header: load i, cmp i < 10, cond br body/exit
861
-        let cur = push_inst(&mut f, header,
862
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
964
+        let cur = push_inst(
965
+            &mut f,
966
+            header,
967
+            InstKind::Load(slot),
968
+            IrType::Int(IntWidth::I32),
863969
         );
864
-        let c10 = push_inst(&mut f, header,
970
+        let c10 = push_inst(
971
+            &mut f,
972
+            header,
865973
             InstKind::ConstInt(10, IntWidth::I32),
866974
             IrType::Int(IntWidth::I32),
867975
         );
868
-        let cmp = push_inst(&mut f, header,
976
+        let cmp = push_inst(
977
+            &mut f,
978
+            header,
869979
             InstKind::ICmp(CmpOp::Lt, cur, c10),
870980
             IrType::Bool,
871981
         );
872982
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
873
-            cond: cmp, true_dest: body, true_args: vec![],
874
-            false_dest: exit, false_args: vec![],
983
+            cond: cmp,
984
+            true_dest: body,
985
+            true_args: vec![],
986
+            false_dest: exit,
987
+            false_args: vec![],
875988
         });
876989
 
877990
         // body: i = i + 1; br header
878
-        let cur2 = push_inst(&mut f, body,
879
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
991
+        let cur2 = push_inst(
992
+            &mut f,
993
+            body,
994
+            InstKind::Load(slot),
995
+            IrType::Int(IntWidth::I32),
880996
         );
881
-        let c1 = push_inst(&mut f, body,
997
+        let c1 = push_inst(
998
+            &mut f,
999
+            body,
8821000
             InstKind::ConstInt(1, IntWidth::I32),
8831001
             IrType::Int(IntWidth::I32),
8841002
         );
885
-        let next = push_inst(&mut f, body,
1003
+        let next = push_inst(
1004
+            &mut f,
1005
+            body,
8861006
             InstKind::IAdd(cur2, c1),
8871007
             IrType::Int(IntWidth::I32),
8881008
         );
889
-        push_inst(&mut f, body,
890
-            InstKind::Store(next, slot), IrType::Void,
891
-        );
1009
+        push_inst(&mut f, body, InstKind::Store(next, slot), IrType::Void);
8921010
         f.block_mut(body).terminator = Some(Terminator::Branch(header, vec![]));
8931011
 
8941012
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
@@ -901,17 +1019,26 @@ mod tests {
9011019
         let f = &m.functions[0];
9021020
         let header_block = f.block(header);
9031021
         // Header should have exactly one block param (the promoted counter).
904
-        assert_eq!(header_block.params.len(), 1,
905
-            "header should have 1 block param for the promoted counter");
1022
+        assert_eq!(
1023
+            header_block.params.len(),
1024
+            1,
1025
+            "header should have 1 block param for the promoted counter"
1026
+        );
9061027
         // No loads or stores anywhere.
9071028
         for b in &f.blocks {
9081029
             for i in &b.insts {
909
-                assert!(!matches!(i.kind, InstKind::Load(_)),
910
-                    "no loads should survive mem2reg");
911
-                assert!(!matches!(i.kind, InstKind::Store(..)),
912
-                    "no stores should survive mem2reg");
913
-                assert!(!matches!(i.kind, InstKind::Alloca(_)),
914
-                    "no allocas should survive mem2reg");
1030
+                assert!(
1031
+                    !matches!(i.kind, InstKind::Load(_)),
1032
+                    "no loads should survive mem2reg"
1033
+                );
1034
+                assert!(
1035
+                    !matches!(i.kind, InstKind::Store(..)),
1036
+                    "no stores should survive mem2reg"
1037
+                );
1038
+                assert!(
1039
+                    !matches!(i.kind, InstKind::Alloca(_)),
1040
+                    "no allocas should survive mem2reg"
1041
+                );
9151042
             }
9161043
         }
9171044
     }
@@ -926,11 +1053,15 @@ mod tests {
9261053
         let mut m = Module::new("t".into());
9271054
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
9281055
         let entry = f.entry;
929
-        let slot = push_inst(&mut f, entry,
1056
+        let slot = push_inst(
1057
+            &mut f,
1058
+            entry,
9301059
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
9311060
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
9321061
         );
933
-        let loaded = push_inst(&mut f, entry,
1062
+        let loaded = push_inst(
1063
+            &mut f,
1064
+            entry,
9341065
             InstKind::Load(slot),
9351066
             IrType::Int(IntWidth::I32),
9361067
         );
@@ -943,7 +1074,9 @@ mod tests {
9431074
 
9441075
         // Return should reference the synthetic Undef.
9451076
         let f = &m.functions[0];
946
-        let undef_id = f.blocks[0].insts.iter()
1077
+        let undef_id = f.blocks[0]
1078
+            .insts
1079
+            .iter()
9471080
             .find(|i| matches!(i.kind, InstKind::Undef(_)))
9481081
             .map(|i| i.id)
9491082
             .expect("no Undef inserted");
@@ -965,16 +1098,22 @@ mod tests {
9651098
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
9661099
         let entry = f.entry;
9671100
 
968
-        let slot = push_inst(&mut f, entry,
1101
+        let slot = push_inst(
1102
+            &mut f,
1103
+            entry,
9691104
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
9701105
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
9711106
         );
972
-        let c1 = push_inst(&mut f, entry,
1107
+        let c1 = push_inst(
1108
+            &mut f,
1109
+            entry,
9731110
             InstKind::ConstInt(1, IntWidth::I32),
9741111
             IrType::Int(IntWidth::I32),
9751112
         );
9761113
         push_inst(&mut f, entry, InstKind::Store(c1, slot), IrType::Void);
977
-        let loaded = push_inst(&mut f, entry,
1114
+        let loaded = push_inst(
1115
+            &mut f,
1116
+            entry,
9781117
             InstKind::Load(slot),
9791118
             IrType::Int(IntWidth::I32),
9801119
         );
@@ -984,7 +1123,9 @@ mod tests {
9841123
         // Nothing branches to it from entry, so prune_unreachable
9851124
         // should remove it before the rename walk.
9861125
         let dead = f.create_block("dead");
987
-        let c99 = push_inst(&mut f, dead,
1126
+        let c99 = push_inst(
1127
+            &mut f,
1128
+            dead,
9881129
             InstKind::ConstInt(99, IntWidth::I32),
9891130
             IrType::Int(IntWidth::I32),
9901131
         );
@@ -995,22 +1136,38 @@ mod tests {
9951136
 
9961137
         assert!(Mem2Reg.run(&mut m));
9971138
         let errs = verify_module(&m);
998
-        assert!(errs.is_empty(),
999
-            "post-mem2reg IR invalid (unreachable store regression): {:?}", errs);
1139
+        assert!(
1140
+            errs.is_empty(),
1141
+            "post-mem2reg IR invalid (unreachable store regression): {:?}",
1142
+            errs
1143
+        );
10001144
 
10011145
         let f = &m.functions[0];
10021146
         // The dead block must be gone (pruned by Phase 0).
1003
-        assert!(!f.blocks.iter().any(|b| b.id == dead),
1004
-            "unreachable block should be pruned by mem2reg Phase 0");
1147
+        assert!(
1148
+            !f.blocks.iter().any(|b| b.id == dead),
1149
+            "unreachable block should be pruned by mem2reg Phase 0"
1150
+        );
10051151
         // The promoted alloca and its load/store should be gone.
10061152
         let entry_block = f.block(f.entry);
1007
-        assert!(!entry_block.insts.iter().any(|i| matches!(i.kind, InstKind::Alloca(_))));
1008
-        assert!(!entry_block.insts.iter().any(|i| matches!(i.kind, InstKind::Load(_))));
1009
-        assert!(!entry_block.insts.iter().any(|i| matches!(i.kind, InstKind::Store(..))));
1153
+        assert!(!entry_block
1154
+            .insts
1155
+            .iter()
1156
+            .any(|i| matches!(i.kind, InstKind::Alloca(_))));
1157
+        assert!(!entry_block
1158
+            .insts
1159
+            .iter()
1160
+            .any(|i| matches!(i.kind, InstKind::Load(_))));
1161
+        assert!(!entry_block
1162
+            .insts
1163
+            .iter()
1164
+            .any(|i| matches!(i.kind, InstKind::Store(..))));
10101165
         // Return must reference c1 (the live store value).
10111166
         match entry_block.terminator.as_ref().unwrap() {
1012
-            Terminator::Return(Some(v)) => assert_eq!(*v, c1,
1013
-                "return should reach c1 directly, not the dead block's c99"),
1167
+            Terminator::Return(Some(v)) => assert_eq!(
1168
+                *v, c1,
1169
+                "return should reach c1 directly, not the dead block's c99"
1170
+            ),
10141171
             _ => panic!(),
10151172
         }
10161173
     }
@@ -1025,11 +1182,15 @@ mod tests {
10251182
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
10261183
         let entry = f.entry;
10271184
 
1028
-        let slot = push_inst(&mut f, entry,
1185
+        let slot = push_inst(
1186
+            &mut f,
1187
+            entry,
10291188
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
10301189
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
10311190
         );
1032
-        let c1 = push_inst(&mut f, entry,
1191
+        let c1 = push_inst(
1192
+            &mut f,
1193
+            entry,
10331194
             InstKind::ConstInt(1, IntWidth::I32),
10341195
             IrType::Int(IntWidth::I32),
10351196
         );
@@ -1041,9 +1202,7 @@ mod tests {
10411202
         // Conditional branch where both arms target `then_b`. The
10421203
         // pre-fix mem2reg would visit `then_b` twice via the
10431204
         // successor list and double-append the new branch args.
1044
-        let cond = push_inst(&mut f, entry,
1045
-            InstKind::ConstBool(true), IrType::Bool,
1046
-        );
1205
+        let cond = push_inst(&mut f, entry, InstKind::ConstBool(true), IrType::Bool);
10471206
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
10481207
             cond,
10491208
             true_dest: then_b,
@@ -1053,7 +1212,9 @@ mod tests {
10531212
         });
10541213
 
10551214
         // `then_b` stores a different value, then branches to merge.
1056
-        let c2 = push_inst(&mut f, then_b,
1215
+        let c2 = push_inst(
1216
+            &mut f,
1217
+            then_b,
10571218
             InstKind::ConstInt(2, IntWidth::I32),
10581219
             IrType::Int(IntWidth::I32),
10591220
         );
@@ -1061,8 +1222,11 @@ mod tests {
10611222
         f.block_mut(then_b).terminator = Some(Terminator::Branch(merge, vec![]));
10621223
 
10631224
         // `merge` loads from slot and returns it.
1064
-        let loaded = push_inst(&mut f, merge,
1065
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
1225
+        let loaded = push_inst(
1226
+            &mut f,
1227
+            merge,
1228
+            InstKind::Load(slot),
1229
+            IrType::Int(IntWidth::I32),
10661230
         );
10671231
         f.block_mut(merge).terminator = Some(Terminator::Return(Some(loaded)));
10681232
 
@@ -1070,8 +1234,11 @@ mod tests {
10701234
 
10711235
         assert!(Mem2Reg.run(&mut m));
10721236
         let errs = verify_module(&m);
1073
-        assert!(errs.is_empty(),
1074
-            "post-mem2reg IR invalid (same-target CondBranch regression): {:?}", errs);
1237
+        assert!(
1238
+            errs.is_empty(),
1239
+            "post-mem2reg IR invalid (same-target CondBranch regression): {:?}",
1240
+            errs
1241
+        );
10751242
 
10761243
         // Verify the entry's CondBranch has at most ONE arg per arm
10771244
         // (the new phi-arg added for the promoted slot). Pre-fix it
@@ -1079,11 +1246,21 @@ mod tests {
10791246
         let f = &m.functions[0];
10801247
         let entry_block = f.block(f.entry);
10811248
         match entry_block.terminator.as_ref().unwrap() {
1082
-            Terminator::CondBranch { true_args, false_args, .. } => {
1083
-                assert!(true_args.len() <= 1,
1084
-                    "true_args double-appended: {:?}", true_args);
1085
-                assert!(false_args.len() <= 1,
1086
-                    "false_args double-appended: {:?}", false_args);
1249
+            Terminator::CondBranch {
1250
+                true_args,
1251
+                false_args,
1252
+                ..
1253
+            } => {
1254
+                assert!(
1255
+                    true_args.len() <= 1,
1256
+                    "true_args double-appended: {:?}",
1257
+                    true_args
1258
+                );
1259
+                assert!(
1260
+                    false_args.len() <= 1,
1261
+                    "false_args double-appended: {:?}",
1262
+                    false_args
1263
+                );
10871264
             }
10881265
             // mem2reg may have collapsed the cond_branch to a
10891266
             // direct branch if the cond was constant; that's
@@ -1115,14 +1292,20 @@ mod tests {
11151292
 
11161293
         // The dead block is unreachable; it should not appear in
11171294
         // the DF map at all.
1118
-        assert!(!df.contains_key(&dead),
1119
-            "DF map should not contain unreachable block, got {:?}", df);
1295
+        assert!(
1296
+            !df.contains_key(&dead),
1297
+            "DF map should not contain unreachable block, got {:?}",
1298
+            df
1299
+        );
11201300
         // The merge block has only ONE reachable predecessor
11211301
         // (entry), so it isn't a true join point and merge ∉ any
11221302
         // DF set.
11231303
         for (b, frontier) in &df {
1124
-            assert!(!frontier.contains(&merge),
1125
-                "merge should not be in DF[{:?}]: only one reachable pred", b);
1304
+            assert!(
1305
+                !frontier.contains(&merge),
1306
+                "merge should not be in DF[{:?}]: only one reachable pred",
1307
+                b
1308
+            );
11261309
         }
11271310
     }
11281311
 
@@ -1137,32 +1320,58 @@ mod tests {
11371320
         let mut m = Module::new("t".into());
11381321
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
11391322
         let entry = f.entry;
1140
-        let slot = push_inst(&mut f, entry,
1323
+        let slot = push_inst(
1324
+            &mut f,
1325
+            entry,
11411326
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
11421327
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11431328
         );
11441329
         // Two loads with no intervening store.
1145
-        let l1 = push_inst(&mut f, entry,
1146
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
1330
+        let l1 = push_inst(
1331
+            &mut f,
1332
+            entry,
1333
+            InstKind::Load(slot),
1334
+            IrType::Int(IntWidth::I32),
11471335
         );
1148
-        let _ = push_inst(&mut f, entry,
1149
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
1336
+        let _ = push_inst(
1337
+            &mut f,
1338
+            entry,
1339
+            InstKind::Load(slot),
1340
+            IrType::Int(IntWidth::I32),
11501341
         );
11511342
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(l1)));
11521343
         m.add_function(f);
11531344
 
1154
-        assert!(Mem2Reg.run(&mut m), "no-store alloca should still be promotable");
1345
+        assert!(
1346
+            Mem2Reg.run(&mut m),
1347
+            "no-store alloca should still be promotable"
1348
+        );
11551349
         let errs = verify_module(&m);
11561350
         assert!(errs.is_empty(), "post-mem2reg IR invalid: {:?}", errs);
11571351
 
11581352
         let block = &m.functions[0].blocks[0];
1159
-        assert!(!block.insts.iter().any(|i| matches!(i.kind, InstKind::Alloca(_))),
1160
-            "alloca should be gone");
1161
-        assert!(!block.insts.iter().any(|i| matches!(i.kind, InstKind::Load(_))),
1162
-            "loads should be gone");
1353
+        assert!(
1354
+            !block
1355
+                .insts
1356
+                .iter()
1357
+                .any(|i| matches!(i.kind, InstKind::Alloca(_))),
1358
+            "alloca should be gone"
1359
+        );
1360
+        assert!(
1361
+            !block
1362
+                .insts
1363
+                .iter()
1364
+                .any(|i| matches!(i.kind, InstKind::Load(_))),
1365
+            "loads should be gone"
1366
+        );
11631367
         // Both loads should be replaced by an Undef sentinel.
1164
-        assert!(block.insts.iter().any(|i| matches!(i.kind, InstKind::Undef(_))),
1165
-            "Undef sentinel should be inserted");
1368
+        assert!(
1369
+            block
1370
+                .insts
1371
+                .iter()
1372
+                .any(|i| matches!(i.kind, InstKind::Undef(_))),
1373
+            "Undef sentinel should be inserted"
1374
+        );
11661375
     }
11671376
 
11681377
     // =============================================================
@@ -1178,19 +1387,21 @@ mod tests {
11781387
         let entry = f.entry;
11791388
 
11801389
         // bag: a Ptr<Ptr<i32>> slot that we'll write the escape into.
1181
-        let bag = push_inst(&mut f, entry,
1390
+        let bag = push_inst(
1391
+            &mut f,
1392
+            entry,
11821393
             InstKind::Alloca(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32)))),
11831394
             IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))))),
11841395
         );
11851396
         // escapee: the alloca whose address we leak.
1186
-        let escapee = push_inst(&mut f, entry,
1397
+        let escapee = push_inst(
1398
+            &mut f,
1399
+            entry,
11871400
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
11881401
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
11891402
         );
11901403
         // Store the escapee POINTER into bag — escapee escapes.
1191
-        push_inst(&mut f, entry,
1192
-            InstKind::Store(escapee, bag), IrType::Void,
1193
-        );
1404
+        push_inst(&mut f, entry, InstKind::Store(escapee, bag), IrType::Void);
11941405
         f.block_mut(entry).terminator = Some(Terminator::Return(None));
11951406
         m.add_function(f);
11961407
 
@@ -1202,7 +1413,9 @@ mod tests {
12021413
         assert!(errs.is_empty(), "post-mem2reg IR invalid: {:?}", errs);
12031414
 
12041415
         let block = &m.functions[0].blocks[0];
1205
-        let surviving_allocas = block.insts.iter()
1416
+        let surviving_allocas = block
1417
+            .insts
1418
+            .iter()
12061419
             .filter(|i| matches!(i.kind, InstKind::Alloca(_)))
12071420
             .count();
12081421
         assert!(
@@ -1222,7 +1435,9 @@ mod tests {
12221435
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
12231436
         let entry = f.entry;
12241437
 
1225
-        let slot = push_inst(&mut f, entry,
1438
+        let slot = push_inst(
1439
+            &mut f,
1440
+            entry,
12261441
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
12271442
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
12281443
         );
@@ -1231,31 +1446,46 @@ mod tests {
12311446
         let else_b = f.create_block("else");
12321447
         let merge = f.create_block("merge");
12331448
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
1234
-            cond, true_dest: then_b, true_args: vec![],
1235
-            false_dest: else_b, false_args: vec![],
1449
+            cond,
1450
+            true_dest: then_b,
1451
+            true_args: vec![],
1452
+            false_dest: else_b,
1453
+            false_args: vec![],
12361454
         });
12371455
 
1238
-        let c1 = push_inst(&mut f, then_b,
1239
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32),
1456
+        let c1 = push_inst(
1457
+            &mut f,
1458
+            then_b,
1459
+            InstKind::ConstInt(1, IntWidth::I32),
1460
+            IrType::Int(IntWidth::I32),
12401461
         );
12411462
         push_inst(&mut f, then_b, InstKind::Store(c1, slot), IrType::Void);
12421463
         f.block_mut(then_b).terminator = Some(Terminator::Branch(merge, vec![]));
12431464
 
1244
-        let c2 = push_inst(&mut f, else_b,
1245
-            InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32),
1465
+        let c2 = push_inst(
1466
+            &mut f,
1467
+            else_b,
1468
+            InstKind::ConstInt(2, IntWidth::I32),
1469
+            IrType::Int(IntWidth::I32),
12461470
         );
12471471
         push_inst(&mut f, else_b, InstKind::Store(c2, slot), IrType::Void);
12481472
         f.block_mut(else_b).terminator = Some(Terminator::Branch(merge, vec![]));
12491473
 
1250
-        let loaded = push_inst(&mut f, merge,
1251
-            InstKind::Load(slot), IrType::Int(IntWidth::I32),
1474
+        let loaded = push_inst(
1475
+            &mut f,
1476
+            merge,
1477
+            InstKind::Load(slot),
1478
+            IrType::Int(IntWidth::I32),
12521479
         );
12531480
         f.block_mut(merge).terminator = Some(Terminator::Return(Some(loaded)));
12541481
         m.add_function(f);
12551482
 
12561483
         assert!(Mem2Reg.run(&mut m), "first run should promote");
12571484
         // Second run must be a no-op: nothing left to promote.
1258
-        assert!(!Mem2Reg.run(&mut m), "second run on already-promoted IR should be a no-op");
1485
+        assert!(
1486
+            !Mem2Reg.run(&mut m),
1487
+            "second run on already-promoted IR should be a no-op"
1488
+        );
12591489
         let errs = verify_module(&m);
12601490
         assert!(errs.is_empty(), "post-mem2reg IR invalid: {:?}", errs);
12611491
     }
@@ -1271,11 +1501,15 @@ mod tests {
12711501
         let mut f = Function::new("f".into(), vec![], IrType::Int(IntWidth::I32));
12721502
         let entry = f.entry;
12731503
 
1274
-        let slot_a = push_inst(&mut f, entry,
1504
+        let slot_a = push_inst(
1505
+            &mut f,
1506
+            entry,
12751507
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
12761508
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
12771509
         );
1278
-        let slot_b = push_inst(&mut f, entry,
1510
+        let slot_b = push_inst(
1511
+            &mut f,
1512
+            entry,
12791513
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
12801514
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
12811515
         );
@@ -1284,35 +1518,66 @@ mod tests {
12841518
         let else_b = f.create_block("else");
12851519
         let merge = f.create_block("merge");
12861520
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
1287
-            cond, true_dest: then_b, true_args: vec![],
1288
-            false_dest: else_b, false_args: vec![],
1521
+            cond,
1522
+            true_dest: then_b,
1523
+            true_args: vec![],
1524
+            false_dest: else_b,
1525
+            false_args: vec![],
12891526
         });
12901527
 
12911528
         // then: a=1, b=10
1292
-        let c1 = push_inst(&mut f, then_b,
1293
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1294
-        let c10 = push_inst(&mut f, then_b,
1295
-            InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32));
1529
+        let c1 = push_inst(
1530
+            &mut f,
1531
+            then_b,
1532
+            InstKind::ConstInt(1, IntWidth::I32),
1533
+            IrType::Int(IntWidth::I32),
1534
+        );
1535
+        let c10 = push_inst(
1536
+            &mut f,
1537
+            then_b,
1538
+            InstKind::ConstInt(10, IntWidth::I32),
1539
+            IrType::Int(IntWidth::I32),
1540
+        );
12961541
         push_inst(&mut f, then_b, InstKind::Store(c1, slot_a), IrType::Void);
12971542
         push_inst(&mut f, then_b, InstKind::Store(c10, slot_b), IrType::Void);
12981543
         f.block_mut(then_b).terminator = Some(Terminator::Branch(merge, vec![]));
12991544
 
13001545
         // else: a=2, b=20
1301
-        let c2 = push_inst(&mut f, else_b,
1302
-            InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32));
1303
-        let c20 = push_inst(&mut f, else_b,
1304
-            InstKind::ConstInt(20, IntWidth::I32), IrType::Int(IntWidth::I32));
1546
+        let c2 = push_inst(
1547
+            &mut f,
1548
+            else_b,
1549
+            InstKind::ConstInt(2, IntWidth::I32),
1550
+            IrType::Int(IntWidth::I32),
1551
+        );
1552
+        let c20 = push_inst(
1553
+            &mut f,
1554
+            else_b,
1555
+            InstKind::ConstInt(20, IntWidth::I32),
1556
+            IrType::Int(IntWidth::I32),
1557
+        );
13051558
         push_inst(&mut f, else_b, InstKind::Store(c2, slot_a), IrType::Void);
13061559
         push_inst(&mut f, else_b, InstKind::Store(c20, slot_b), IrType::Void);
13071560
         f.block_mut(else_b).terminator = Some(Terminator::Branch(merge, vec![]));
13081561
 
13091562
         // merge: result = a + b
1310
-        let la = push_inst(&mut f, merge,
1311
-            InstKind::Load(slot_a), IrType::Int(IntWidth::I32));
1312
-        let lb = push_inst(&mut f, merge,
1313
-            InstKind::Load(slot_b), IrType::Int(IntWidth::I32));
1314
-        let sum = push_inst(&mut f, merge,
1315
-            InstKind::IAdd(la, lb), IrType::Int(IntWidth::I32));
1563
+        let la = push_inst(
1564
+            &mut f,
1565
+            merge,
1566
+            InstKind::Load(slot_a),
1567
+            IrType::Int(IntWidth::I32),
1568
+        );
1569
+        let lb = push_inst(
1570
+            &mut f,
1571
+            merge,
1572
+            InstKind::Load(slot_b),
1573
+            IrType::Int(IntWidth::I32),
1574
+        );
1575
+        let sum = push_inst(
1576
+            &mut f,
1577
+            merge,
1578
+            InstKind::IAdd(la, lb),
1579
+            IrType::Int(IntWidth::I32),
1580
+        );
13161581
         f.block_mut(merge).terminator = Some(Terminator::Return(Some(sum)));
13171582
         m.add_function(f);
13181583
 
@@ -1322,14 +1587,21 @@ mod tests {
13221587
 
13231588
         let f = &m.functions[0];
13241589
         let merge_block = f.block(merge);
1325
-        assert_eq!(merge_block.params.len(), 2,
1326
-            "merge should have 2 block params, one per promoted alloca");
1590
+        assert_eq!(
1591
+            merge_block.params.len(),
1592
+            2,
1593
+            "merge should have 2 block params, one per promoted alloca"
1594
+        );
13271595
         // Each predecessor must now carry 2 branch args.
13281596
         for pred in [then_b, else_b] {
13291597
             let term = f.block(pred).terminator.as_ref().unwrap();
13301598
             match term {
1331
-                Terminator::Branch(_, args) => assert_eq!(args.len(), 2,
1332
-                    "predecessor {:?} should pass 2 args to merge", pred),
1599
+                Terminator::Branch(_, args) => assert_eq!(
1600
+                    args.len(),
1601
+                    2,
1602
+                    "predecessor {:?} should pass 2 args to merge",
1603
+                    pred
1604
+                ),
13331605
                 _ => panic!("predecessor terminator should be Branch"),
13341606
             }
13351607
         }
@@ -1411,14 +1683,24 @@ mod tests {
14111683
             InstKind::Load(save_slot),
14121684
             IrType::Int(IntWidth::I32),
14131685
         );
1414
-        push_inst(&mut f, then_b, InstKind::Store(then_load, tmp_slot), IrType::Void);
1686
+        push_inst(
1687
+            &mut f,
1688
+            then_b,
1689
+            InstKind::Store(then_load, tmp_slot),
1690
+            IrType::Void,
1691
+        );
14151692
         let then_tmp = push_inst(
14161693
             &mut f,
14171694
             then_b,
14181695
             InstKind::Load(tmp_slot),
14191696
             IrType::Int(IntWidth::I32),
14201697
         );
1421
-        push_inst(&mut f, then_b, InstKind::Store(then_tmp, result_slot), IrType::Void);
1698
+        push_inst(
1699
+            &mut f,
1700
+            then_b,
1701
+            InstKind::Store(then_tmp, result_slot),
1702
+            IrType::Void,
1703
+        );
14221704
         f.block_mut(then_b).terminator = Some(Terminator::Branch(merge, vec![]));
14231705
 
14241706
         let else_load = push_inst(
@@ -1427,7 +1709,12 @@ mod tests {
14271709
             InstKind::Load(save_slot),
14281710
             IrType::Int(IntWidth::I32),
14291711
         );
1430
-        push_inst(&mut f, else_b, InstKind::Store(else_load, tmp_slot), IrType::Void);
1712
+        push_inst(
1713
+            &mut f,
1714
+            else_b,
1715
+            InstKind::Store(else_load, tmp_slot),
1716
+            IrType::Void,
1717
+        );
14311718
         let else_tmp = push_inst(
14321719
             &mut f,
14331720
             else_b,
@@ -1446,7 +1733,12 @@ mod tests {
14461733
             InstKind::IAdd(else_tmp, one),
14471734
             IrType::Int(IntWidth::I32),
14481735
         );
1449
-        push_inst(&mut f, else_b, InstKind::Store(bumped, result_slot), IrType::Void);
1736
+        push_inst(
1737
+            &mut f,
1738
+            else_b,
1739
+            InstKind::Store(bumped, result_slot),
1740
+            IrType::Void,
1741
+        );
14501742
         f.block_mut(else_b).terminator = Some(Terminator::Branch(merge, vec![]));
14511743
 
14521744
         let merged = push_inst(
@@ -1470,7 +1762,10 @@ mod tests {
14701762
         for block in &f.blocks {
14711763
             for inst in &block.insts {
14721764
                 assert!(
1473
-                    !matches!(inst.kind, InstKind::Alloca(_) | InstKind::Load(_) | InstKind::Store(_, _)),
1765
+                    !matches!(
1766
+                        inst.kind,
1767
+                        InstKind::Alloca(_) | InstKind::Load(_) | InstKind::Store(_, _)
1768
+                    ),
14741769
                     "promoted branchy scalar should leave no memory traffic, found {:?}",
14751770
                     inst.kind
14761771
                 );
@@ -1489,12 +1784,18 @@ mod tests {
14891784
         let mut f = Function::new("f".into(), vec![], IrType::Void);
14901785
         let entry = f.entry;
14911786
 
1492
-        let slot = push_inst(&mut f, entry,
1787
+        let slot = push_inst(
1788
+            &mut f,
1789
+            entry,
14931790
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
14941791
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
14951792
         );
1496
-        let c0 = push_inst(&mut f, entry,
1497
-            InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
1793
+        let c0 = push_inst(
1794
+            &mut f,
1795
+            entry,
1796
+            InstKind::ConstInt(0, IntWidth::I32),
1797
+            IrType::Int(IntWidth::I32),
1798
+        );
14981799
         push_inst(&mut f, entry, InstKind::Store(c0, slot), IrType::Void);
14991800
 
15001801
         let header = f.create_block("header");
@@ -1503,30 +1804,65 @@ mod tests {
15031804
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![]));
15041805
 
15051806
         // header: i = load slot; cmp i < 5
1506
-        let cur = push_inst(&mut f, header,
1507
-            InstKind::Load(slot), IrType::Int(IntWidth::I32));
1508
-        let c5 = push_inst(&mut f, header,
1509
-            InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32));
1510
-        let cmp = push_inst(&mut f, header,
1511
-            InstKind::ICmp(CmpOp::Lt, cur, c5), IrType::Bool);
1807
+        let cur = push_inst(
1808
+            &mut f,
1809
+            header,
1810
+            InstKind::Load(slot),
1811
+            IrType::Int(IntWidth::I32),
1812
+        );
1813
+        let c5 = push_inst(
1814
+            &mut f,
1815
+            header,
1816
+            InstKind::ConstInt(5, IntWidth::I32),
1817
+            IrType::Int(IntWidth::I32),
1818
+        );
1819
+        let cmp = push_inst(
1820
+            &mut f,
1821
+            header,
1822
+            InstKind::ICmp(CmpOp::Lt, cur, c5),
1823
+            IrType::Bool,
1824
+        );
15121825
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
1513
-            cond: cmp, true_dest: body, true_args: vec![],
1514
-            false_dest: exit, false_args: vec![],
1826
+            cond: cmp,
1827
+            true_dest: body,
1828
+            true_args: vec![],
1829
+            false_dest: exit,
1830
+            false_args: vec![],
15151831
         });
15161832
 
15171833
         // body: store cur+1 to slot, then store (cur+1)+10 to slot.
15181834
         // The SECOND store is the one that should flow to header.
1519
-        let c1 = push_inst(&mut f, body,
1520
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1521
-        let cur2 = push_inst(&mut f, body,
1522
-            InstKind::Load(slot), IrType::Int(IntWidth::I32));
1523
-        let plus1 = push_inst(&mut f, body,
1524
-            InstKind::IAdd(cur2, c1), IrType::Int(IntWidth::I32));
1835
+        let c1 = push_inst(
1836
+            &mut f,
1837
+            body,
1838
+            InstKind::ConstInt(1, IntWidth::I32),
1839
+            IrType::Int(IntWidth::I32),
1840
+        );
1841
+        let cur2 = push_inst(
1842
+            &mut f,
1843
+            body,
1844
+            InstKind::Load(slot),
1845
+            IrType::Int(IntWidth::I32),
1846
+        );
1847
+        let plus1 = push_inst(
1848
+            &mut f,
1849
+            body,
1850
+            InstKind::IAdd(cur2, c1),
1851
+            IrType::Int(IntWidth::I32),
1852
+        );
15251853
         push_inst(&mut f, body, InstKind::Store(plus1, slot), IrType::Void);
1526
-        let c10 = push_inst(&mut f, body,
1527
-            InstKind::ConstInt(10, IntWidth::I32), IrType::Int(IntWidth::I32));
1528
-        let plus10 = push_inst(&mut f, body,
1529
-            InstKind::IAdd(plus1, c10), IrType::Int(IntWidth::I32));
1854
+        let c10 = push_inst(
1855
+            &mut f,
1856
+            body,
1857
+            InstKind::ConstInt(10, IntWidth::I32),
1858
+            IrType::Int(IntWidth::I32),
1859
+        );
1860
+        let plus10 = push_inst(
1861
+            &mut f,
1862
+            body,
1863
+            InstKind::IAdd(plus1, c10),
1864
+            IrType::Int(IntWidth::I32),
1865
+        );
15301866
         push_inst(&mut f, body, InstKind::Store(plus10, slot), IrType::Void);
15311867
         f.block_mut(body).terminator = Some(Terminator::Branch(header, vec![]));
15321868
 
@@ -1541,8 +1877,14 @@ mod tests {
15411877
         // No loads/stores/allocas anywhere.
15421878
         for b in &f.blocks {
15431879
             for i in &b.insts {
1544
-                assert!(!matches!(i.kind, InstKind::Load(_) | InstKind::Store(..) | InstKind::Alloca(_)),
1545
-                    "should be promoted away: {:?}", i.kind);
1880
+                assert!(
1881
+                    !matches!(
1882
+                        i.kind,
1883
+                        InstKind::Load(_) | InstKind::Store(..) | InstKind::Alloca(_)
1884
+                    ),
1885
+                    "should be promoted away: {:?}",
1886
+                    i.kind
1887
+                );
15461888
             }
15471889
         }
15481890
         // body's branch back to header should pass `plus10` (the
@@ -1551,8 +1893,10 @@ mod tests {
15511893
         match body_term {
15521894
             Terminator::Branch(_, args) => {
15531895
                 assert_eq!(args.len(), 1, "body should pass 1 arg to header");
1554
-                assert_eq!(args[0], plus10,
1555
-                    "header arg should be the LAST store value, not the first");
1896
+                assert_eq!(
1897
+                    args[0], plus10,
1898
+                    "header arg should be the LAST store value, not the first"
1899
+                );
15561900
             }
15571901
             _ => panic!("body terminator should be Branch"),
15581902
         }
@@ -1569,12 +1913,18 @@ mod tests {
15691913
         let mut f = Function::new("f".into(), vec![], IrType::Void);
15701914
         let entry = f.entry;
15711915
 
1572
-        let slot = push_inst(&mut f, entry,
1916
+        let slot = push_inst(
1917
+            &mut f,
1918
+            entry,
15731919
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
15741920
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
15751921
         );
1576
-        let c0 = push_inst(&mut f, entry,
1577
-            InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
1922
+        let c0 = push_inst(
1923
+            &mut f,
1924
+            entry,
1925
+            InstKind::ConstInt(0, IntWidth::I32),
1926
+            IrType::Int(IntWidth::I32),
1927
+        );
15781928
         push_inst(&mut f, entry, InstKind::Store(c0, slot), IrType::Void);
15791929
 
15801930
         let header = f.create_block("header");
@@ -1585,44 +1935,94 @@ mod tests {
15851935
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![]));
15861936
 
15871937
         // header: i = load; cmp i < 100; cond br body / exit
1588
-        let cur = push_inst(&mut f, header,
1589
-            InstKind::Load(slot), IrType::Int(IntWidth::I32));
1590
-        let c100 = push_inst(&mut f, header,
1591
-            InstKind::ConstInt(100, IntWidth::I32), IrType::Int(IntWidth::I32));
1592
-        let cmp_top = push_inst(&mut f, header,
1593
-            InstKind::ICmp(CmpOp::Lt, cur, c100), IrType::Bool);
1938
+        let cur = push_inst(
1939
+            &mut f,
1940
+            header,
1941
+            InstKind::Load(slot),
1942
+            IrType::Int(IntWidth::I32),
1943
+        );
1944
+        let c100 = push_inst(
1945
+            &mut f,
1946
+            header,
1947
+            InstKind::ConstInt(100, IntWidth::I32),
1948
+            IrType::Int(IntWidth::I32),
1949
+        );
1950
+        let cmp_top = push_inst(
1951
+            &mut f,
1952
+            header,
1953
+            InstKind::ICmp(CmpOp::Lt, cur, c100),
1954
+            IrType::Bool,
1955
+        );
15941956
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
1595
-            cond: cmp_top, true_dest: body, true_args: vec![],
1596
-            false_dest: exit, false_args: vec![],
1957
+            cond: cmp_top,
1958
+            true_dest: body,
1959
+            true_args: vec![],
1960
+            false_dest: exit,
1961
+            false_args: vec![],
15971962
         });
15981963
 
15991964
         // body: branch to latch_a or latch_b based on cur.
1600
-        let c50 = push_inst(&mut f, body,
1601
-            InstKind::ConstInt(50, IntWidth::I32), IrType::Int(IntWidth::I32));
1602
-        let cmp_mid = push_inst(&mut f, body,
1603
-            InstKind::ICmp(CmpOp::Lt, cur, c50), IrType::Bool);
1965
+        let c50 = push_inst(
1966
+            &mut f,
1967
+            body,
1968
+            InstKind::ConstInt(50, IntWidth::I32),
1969
+            IrType::Int(IntWidth::I32),
1970
+        );
1971
+        let cmp_mid = push_inst(
1972
+            &mut f,
1973
+            body,
1974
+            InstKind::ICmp(CmpOp::Lt, cur, c50),
1975
+            IrType::Bool,
1976
+        );
16041977
         f.block_mut(body).terminator = Some(Terminator::CondBranch {
1605
-            cond: cmp_mid, true_dest: latch_a, true_args: vec![],
1606
-            false_dest: latch_b, false_args: vec![],
1978
+            cond: cmp_mid,
1979
+            true_dest: latch_a,
1980
+            true_args: vec![],
1981
+            false_dest: latch_b,
1982
+            false_args: vec![],
16071983
         });
16081984
 
16091985
         // latch_a: store cur+1; jump header
1610
-        let c1a = push_inst(&mut f, latch_a,
1611
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1612
-        let curla = push_inst(&mut f, latch_a,
1613
-            InstKind::Load(slot), IrType::Int(IntWidth::I32));
1614
-        let nexta = push_inst(&mut f, latch_a,
1615
-            InstKind::IAdd(curla, c1a), IrType::Int(IntWidth::I32));
1986
+        let c1a = push_inst(
1987
+            &mut f,
1988
+            latch_a,
1989
+            InstKind::ConstInt(1, IntWidth::I32),
1990
+            IrType::Int(IntWidth::I32),
1991
+        );
1992
+        let curla = push_inst(
1993
+            &mut f,
1994
+            latch_a,
1995
+            InstKind::Load(slot),
1996
+            IrType::Int(IntWidth::I32),
1997
+        );
1998
+        let nexta = push_inst(
1999
+            &mut f,
2000
+            latch_a,
2001
+            InstKind::IAdd(curla, c1a),
2002
+            IrType::Int(IntWidth::I32),
2003
+        );
16162004
         push_inst(&mut f, latch_a, InstKind::Store(nexta, slot), IrType::Void);
16172005
         f.block_mut(latch_a).terminator = Some(Terminator::Branch(header, vec![]));
16182006
 
16192007
         // latch_b: store cur+2; jump header
1620
-        let c2b = push_inst(&mut f, latch_b,
1621
-            InstKind::ConstInt(2, IntWidth::I32), IrType::Int(IntWidth::I32));
1622
-        let curlb = push_inst(&mut f, latch_b,
1623
-            InstKind::Load(slot), IrType::Int(IntWidth::I32));
1624
-        let nextb = push_inst(&mut f, latch_b,
1625
-            InstKind::IAdd(curlb, c2b), IrType::Int(IntWidth::I32));
2008
+        let c2b = push_inst(
2009
+            &mut f,
2010
+            latch_b,
2011
+            InstKind::ConstInt(2, IntWidth::I32),
2012
+            IrType::Int(IntWidth::I32),
2013
+        );
2014
+        let curlb = push_inst(
2015
+            &mut f,
2016
+            latch_b,
2017
+            InstKind::Load(slot),
2018
+            IrType::Int(IntWidth::I32),
2019
+        );
2020
+        let nextb = push_inst(
2021
+            &mut f,
2022
+            latch_b,
2023
+            InstKind::IAdd(curlb, c2b),
2024
+            IrType::Int(IntWidth::I32),
2025
+        );
16262026
         push_inst(&mut f, latch_b, InstKind::Store(nextb, slot), IrType::Void);
16272027
         f.block_mut(latch_b).terminator = Some(Terminator::Branch(header, vec![]));
16282028
 
@@ -1635,8 +2035,11 @@ mod tests {
16352035
 
16362036
         let f = &m.functions[0];
16372037
         let header_block = f.block(header);
1638
-        assert_eq!(header_block.params.len(), 1,
1639
-            "header should have 1 block param for the counter");
2038
+        assert_eq!(
2039
+            header_block.params.len(),
2040
+            1,
2041
+            "header should have 1 block param for the counter"
2042
+        );
16402043
 
16412044
         // Each latch's branch to header should pass exactly one arg
16422045
         // (its computed `next` value).
@@ -1669,75 +2072,156 @@ mod tests {
16692072
         let mut f = Function::new("f".into(), vec![], IrType::Void);
16702073
         let entry = f.entry;
16712074
 
1672
-        let outer_slot = push_inst(&mut f, entry,
2075
+        let outer_slot = push_inst(
2076
+            &mut f,
2077
+            entry,
16732078
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
16742079
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
16752080
         );
1676
-        let inner_slot = push_inst(&mut f, entry,
2081
+        let inner_slot = push_inst(
2082
+            &mut f,
2083
+            entry,
16772084
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
16782085
             IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
16792086
         );
1680
-        let c0 = push_inst(&mut f, entry,
1681
-            InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
2087
+        let c0 = push_inst(
2088
+            &mut f,
2089
+            entry,
2090
+            InstKind::ConstInt(0, IntWidth::I32),
2091
+            IrType::Int(IntWidth::I32),
2092
+        );
16822093
         push_inst(&mut f, entry, InstKind::Store(c0, outer_slot), IrType::Void);
16832094
 
16842095
         let outer_header = f.create_block("outer_header");
1685
-        let inner_init  = f.create_block("inner_init");
2096
+        let inner_init = f.create_block("inner_init");
16862097
         let inner_header = f.create_block("inner_header");
1687
-        let inner_body  = f.create_block("inner_body");
2098
+        let inner_body = f.create_block("inner_body");
16882099
         let outer_latch = f.create_block("outer_latch");
16892100
         let exit = f.create_block("exit");
16902101
 
16912102
         f.block_mut(entry).terminator = Some(Terminator::Branch(outer_header, vec![]));
16922103
 
16932104
         // outer_header: i = load outer; cmp i<3; br inner_init / exit
1694
-        let i = push_inst(&mut f, outer_header,
1695
-            InstKind::Load(outer_slot), IrType::Int(IntWidth::I32));
1696
-        let c3 = push_inst(&mut f, outer_header,
1697
-            InstKind::ConstInt(3, IntWidth::I32), IrType::Int(IntWidth::I32));
1698
-        let cmpo = push_inst(&mut f, outer_header,
1699
-            InstKind::ICmp(CmpOp::Lt, i, c3), IrType::Bool);
2105
+        let i = push_inst(
2106
+            &mut f,
2107
+            outer_header,
2108
+            InstKind::Load(outer_slot),
2109
+            IrType::Int(IntWidth::I32),
2110
+        );
2111
+        let c3 = push_inst(
2112
+            &mut f,
2113
+            outer_header,
2114
+            InstKind::ConstInt(3, IntWidth::I32),
2115
+            IrType::Int(IntWidth::I32),
2116
+        );
2117
+        let cmpo = push_inst(
2118
+            &mut f,
2119
+            outer_header,
2120
+            InstKind::ICmp(CmpOp::Lt, i, c3),
2121
+            IrType::Bool,
2122
+        );
17002123
         f.block_mut(outer_header).terminator = Some(Terminator::CondBranch {
1701
-            cond: cmpo, true_dest: inner_init, true_args: vec![],
1702
-            false_dest: exit, false_args: vec![],
2124
+            cond: cmpo,
2125
+            true_dest: inner_init,
2126
+            true_args: vec![],
2127
+            false_dest: exit,
2128
+            false_args: vec![],
17032129
         });
17042130
 
17052131
         // inner_init: store 0 to inner; br inner_header
1706
-        let c0i = push_inst(&mut f, inner_init,
1707
-            InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
1708
-        push_inst(&mut f, inner_init, InstKind::Store(c0i, inner_slot), IrType::Void);
2132
+        let c0i = push_inst(
2133
+            &mut f,
2134
+            inner_init,
2135
+            InstKind::ConstInt(0, IntWidth::I32),
2136
+            IrType::Int(IntWidth::I32),
2137
+        );
2138
+        push_inst(
2139
+            &mut f,
2140
+            inner_init,
2141
+            InstKind::Store(c0i, inner_slot),
2142
+            IrType::Void,
2143
+        );
17092144
         f.block_mut(inner_init).terminator = Some(Terminator::Branch(inner_header, vec![]));
17102145
 
17112146
         // inner_header: j = load inner; cmp j<5; br inner_body / outer_latch
1712
-        let j = push_inst(&mut f, inner_header,
1713
-            InstKind::Load(inner_slot), IrType::Int(IntWidth::I32));
1714
-        let c5 = push_inst(&mut f, inner_header,
1715
-            InstKind::ConstInt(5, IntWidth::I32), IrType::Int(IntWidth::I32));
1716
-        let cmpi = push_inst(&mut f, inner_header,
1717
-            InstKind::ICmp(CmpOp::Lt, j, c5), IrType::Bool);
2147
+        let j = push_inst(
2148
+            &mut f,
2149
+            inner_header,
2150
+            InstKind::Load(inner_slot),
2151
+            IrType::Int(IntWidth::I32),
2152
+        );
2153
+        let c5 = push_inst(
2154
+            &mut f,
2155
+            inner_header,
2156
+            InstKind::ConstInt(5, IntWidth::I32),
2157
+            IrType::Int(IntWidth::I32),
2158
+        );
2159
+        let cmpi = push_inst(
2160
+            &mut f,
2161
+            inner_header,
2162
+            InstKind::ICmp(CmpOp::Lt, j, c5),
2163
+            IrType::Bool,
2164
+        );
17182165
         f.block_mut(inner_header).terminator = Some(Terminator::CondBranch {
1719
-            cond: cmpi, true_dest: inner_body, true_args: vec![],
1720
-            false_dest: outer_latch, false_args: vec![],
2166
+            cond: cmpi,
2167
+            true_dest: inner_body,
2168
+            true_args: vec![],
2169
+            false_dest: outer_latch,
2170
+            false_args: vec![],
17212171
         });
17222172
 
17232173
         // inner_body: j = j + 1; store inner; br inner_header
1724
-        let c1i = push_inst(&mut f, inner_body,
1725
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1726
-        let jcur = push_inst(&mut f, inner_body,
1727
-            InstKind::Load(inner_slot), IrType::Int(IntWidth::I32));
1728
-        let jnext = push_inst(&mut f, inner_body,
1729
-            InstKind::IAdd(jcur, c1i), IrType::Int(IntWidth::I32));
1730
-        push_inst(&mut f, inner_body, InstKind::Store(jnext, inner_slot), IrType::Void);
2174
+        let c1i = push_inst(
2175
+            &mut f,
2176
+            inner_body,
2177
+            InstKind::ConstInt(1, IntWidth::I32),
2178
+            IrType::Int(IntWidth::I32),
2179
+        );
2180
+        let jcur = push_inst(
2181
+            &mut f,
2182
+            inner_body,
2183
+            InstKind::Load(inner_slot),
2184
+            IrType::Int(IntWidth::I32),
2185
+        );
2186
+        let jnext = push_inst(
2187
+            &mut f,
2188
+            inner_body,
2189
+            InstKind::IAdd(jcur, c1i),
2190
+            IrType::Int(IntWidth::I32),
2191
+        );
2192
+        push_inst(
2193
+            &mut f,
2194
+            inner_body,
2195
+            InstKind::Store(jnext, inner_slot),
2196
+            IrType::Void,
2197
+        );
17312198
         f.block_mut(inner_body).terminator = Some(Terminator::Branch(inner_header, vec![]));
17322199
 
17332200
         // outer_latch: i = i + 1; store outer; br outer_header
1734
-        let c1o = push_inst(&mut f, outer_latch,
1735
-            InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
1736
-        let icur = push_inst(&mut f, outer_latch,
1737
-            InstKind::Load(outer_slot), IrType::Int(IntWidth::I32));
1738
-        let inext = push_inst(&mut f, outer_latch,
1739
-            InstKind::IAdd(icur, c1o), IrType::Int(IntWidth::I32));
1740
-        push_inst(&mut f, outer_latch, InstKind::Store(inext, outer_slot), IrType::Void);
2201
+        let c1o = push_inst(
2202
+            &mut f,
2203
+            outer_latch,
2204
+            InstKind::ConstInt(1, IntWidth::I32),
2205
+            IrType::Int(IntWidth::I32),
2206
+        );
2207
+        let icur = push_inst(
2208
+            &mut f,
2209
+            outer_latch,
2210
+            InstKind::Load(outer_slot),
2211
+            IrType::Int(IntWidth::I32),
2212
+        );
2213
+        let inext = push_inst(
2214
+            &mut f,
2215
+            outer_latch,
2216
+            InstKind::IAdd(icur, c1o),
2217
+            IrType::Int(IntWidth::I32),
2218
+        );
2219
+        push_inst(
2220
+            &mut f,
2221
+            outer_latch,
2222
+            InstKind::Store(inext, outer_slot),
2223
+            IrType::Void,
2224
+        );
17412225
         f.block_mut(outer_latch).terminator = Some(Terminator::Branch(outer_header, vec![]));
17422226
 
17432227
         f.block_mut(exit).terminator = Some(Terminator::Return(None));
@@ -1764,14 +2248,24 @@ mod tests {
17642248
         assert_eq!(f.block(outer_header).params.len(), 2,
17652249
             "outer_header should have exactly 2 params (outer + inner counter via back-edge IDF), got {}",
17662250
             f.block(outer_header).params.len());
1767
-        assert_eq!(f.block(inner_header).params.len(), 1,
2251
+        assert_eq!(
2252
+            f.block(inner_header).params.len(),
2253
+            1,
17682254
             "inner_header should have exactly 1 param for inner counter, got {}",
1769
-            f.block(inner_header).params.len());
2255
+            f.block(inner_header).params.len()
2256
+        );
17702257
         // No loads/stores/allocas anywhere — both slots fully promoted.
17712258
         for b in &f.blocks {
17722259
             for i in &b.insts {
1773
-                assert!(!matches!(i.kind, InstKind::Load(_) | InstKind::Store(..) | InstKind::Alloca(_)),
1774
-                    "{:?}: kind {:?} should be promoted away", b.id, i.kind);
2260
+                assert!(
2261
+                    !matches!(
2262
+                        i.kind,
2263
+                        InstKind::Load(_) | InstKind::Store(..) | InstKind::Alloca(_)
2264
+                    ),
2265
+                    "{:?}: kind {:?} should be promoted away",
2266
+                    b.id,
2267
+                    i.kind
2268
+                );
17752269
             }
17762270
         }
17772271
     }
src/opt/mod.rsmodified
77 lines changed — click to load
@@ -7,42 +7,42 @@
77
 //! invocation is determined by the `OptLevel` selected on the command
88
 //! line (`-O0` through `-Ofast`).
99
 
10
-pub mod pass;
11
-pub mod pipeline;
12
-pub mod util;
10
+pub mod alias;
11
+pub mod bce;
12
+pub mod call_resolve;
13
+pub mod callgraph;
14
+pub mod const_arg;
1315
 pub mod const_fold;
1416
 pub mod const_prop;
15
-pub mod dce;
1617
 pub mod cse;
17
-pub mod strength_reduce;
18
-pub mod licm;
19
-pub mod mem2reg;
20
-pub mod dse;
21
-pub mod lsf;
22
-pub mod unroll;
23
-pub mod loop_tree;
24
-pub mod loop_utils;
25
-pub mod preheader;
26
-pub mod unswitch;
27
-pub mod interchange;
18
+pub mod dce;
19
+pub mod dead_arg;
20
+pub mod dead_func;
2821
 pub mod dep_analysis;
29
-pub mod peel;
22
+pub mod dse;
23
+pub mod fast_math;
3024
 pub mod fission;
3125
 pub mod fusion;
32
-pub mod call_resolve;
33
-pub mod callgraph;
26
+pub mod global_lsf;
27
+pub mod gvn;
3428
 pub mod inline;
35
-pub mod simplify_cfg;
36
-pub mod dead_func;
37
-pub mod dead_arg;
38
-pub mod const_arg;
29
+pub mod interchange;
30
+pub mod licm;
31
+pub mod loop_tree;
32
+pub mod loop_utils;
33
+pub mod lsf;
34
+pub mod mem2reg;
35
+pub mod pass;
36
+pub mod peel;
37
+pub mod pipeline;
38
+pub mod preheader;
3939
 pub mod return_prop;
40
-pub mod fast_math;
40
+pub mod simplify_cfg;
4141
 pub mod sroa;
42
-pub mod alias;
43
-pub mod gvn;
44
-pub mod global_lsf;
45
-pub mod bce;
42
+pub mod strength_reduce;
43
+pub mod unroll;
44
+pub mod unswitch;
45
+pub mod util;
4646
 pub mod vectorize;
4747
 
4848
 #[cfg(test)]
@@ -52,7 +52,7 @@ mod audit_tests;
5252
 // driver actually uses. Audit Cos-2: previously every pass was
5353
 // re-exported behind `#[allow(unused_imports)]`, which masked any
5454
 // future regressions that orphaned a re-export.
55
-pub use pipeline::{OptLevel, build_i128_pipeline, build_pipeline};
55
+pub use pipeline::{build_i128_pipeline, build_pipeline, OptLevel};
5656
 
5757
 // Test-only re-export so audit_tests can refer to passes by their
5858
 // short name without the full module path.
src/opt/pass.rsmodified
64 lines changed — click to load
@@ -95,7 +95,10 @@ impl PassManager {
9595
             }
9696
         }
9797
 
98
-        PassRunResult { change_count, iterations }
98
+        PassRunResult {
99
+            change_count,
100
+            iterations,
101
+        }
99102
     }
100103
 
101104
     fn verify_or_panic(&self, module: &Module, after: &str) {
@@ -104,10 +107,7 @@ impl PassManager {
104107
         }
105108
         let errors: Vec<VerifyError> = verify_module(module);
106109
         if !errors.is_empty() {
107
-            let mut msg = format!(
108
-                "IR verifier failed after pass `{}`:\n",
109
-                after
110
-            );
110
+            let mut msg = format!("IR verifier failed after pass `{}`:\n", after);
111111
             for e in &errors {
112112
                 msg.push_str("  - ");
113113
                 msg.push_str(&e.msg);
@@ -133,8 +133,12 @@ mod tests {
133133
     /// A pass that does nothing — used to test infrastructure plumbing.
134134
     struct NoopPass;
135135
     impl Pass for NoopPass {
136
-        fn name(&self) -> &'static str { "noop" }
137
-        fn run(&self, _module: &mut Module) -> bool { false }
136
+        fn name(&self) -> &'static str {
137
+            "noop"
138
+        }
139
+        fn run(&self, _module: &mut Module) -> bool {
140
+            false
141
+        }
138142
     }
139143
 
140144
     /// A pass that claims it changed once, then is idle.
@@ -142,9 +146,16 @@ mod tests {
142146
         fired: std::cell::Cell<bool>,
143147
     }
144148
     impl Pass for OneShotPass {
145
-        fn name(&self) -> &'static str { "oneshot" }
149
+        fn name(&self) -> &'static str {
150
+            "oneshot"
151
+        }
146152
         fn run(&self, _module: &mut Module) -> bool {
147
-            if self.fired.get() { false } else { self.fired.set(true); true }
153
+            if self.fired.get() {
154
+                false
155
+            } else {
156
+                self.fired.set(true);
157
+                true
158
+            }
148159
         }
149160
     }
150161
 
@@ -182,7 +193,9 @@ mod tests {
182193
     #[test]
183194
     fn oneshot_runs_then_terminates() {
184195
         let mut pm = PassManager::new();
185
-        pm.add(Box::new(OneShotPass { fired: std::cell::Cell::new(false) }));
196
+        pm.add(Box::new(OneShotPass {
197
+            fired: std::cell::Cell::new(false),
198
+        }));
186199
         let mut m = empty_module();
187200
         let r = pm.run(&mut m);
188201
         assert_eq!(r.change_count, 1);
src/opt/peel.rsmodified
268 lines changed — click to load
@@ -12,22 +12,26 @@
1212
 //! peeled iteration. Later const-prop folds `iv=init_const` through the
1313
 //! clone, turning `if (i==1)` into `if (true)` and eliminating dead code.
1414
 
15
-use std::collections::HashSet;
15
+use super::loop_utils::{clone_loop, find_preheader, loop_defined_values, resolve_const_int};
16
+use super::pass::Pass;
1617
 use crate::ir::inst::*;
1718
 use crate::ir::types::IrType;
1819
 use crate::ir::walk::{find_natural_loops, predecessors};
19
-use super::loop_utils::{find_preheader, resolve_const_int, loop_defined_values, clone_loop};
20
-use super::pass::Pass;
20
+use std::collections::HashSet;
2121
 
2222
 pub struct LoopPeel;
2323
 
2424
 impl Pass for LoopPeel {
25
-    fn name(&self) -> &'static str { "loop-peel" }
25
+    fn name(&self) -> &'static str {
26
+        "loop-peel"
27
+    }
2628
 
2729
     fn run(&self, module: &mut Module) -> bool {
2830
         let mut changed = false;
2931
         for func in &mut module.functions {
30
-            if peel_in_function(func) { changed = true; }
32
+            if peel_in_function(func) {
33
+                changed = true;
34
+            }
3135
         }
3236
         changed
3337
     }
@@ -38,31 +42,41 @@ fn peel_in_function(func: &mut Function) -> bool {
3842
     let preds = predecessors(func);
3943
 
4044
     for lp in &loops {
41
-        let Some(ph_id) = find_preheader(func, lp, &preds) else { continue };
45
+        let Some(ph_id) = find_preheader(func, lp, &preds) else {
46
+            continue;
47
+        };
4248
 
4349
         // Header must have exactly 1 block param (the IV).
4450
         let hdr = func.block(lp.header);
45
-        if hdr.params.len() != 1 { continue; }
51
+        if hdr.params.len() != 1 {
52
+            continue;
53
+        }
4654
         let iv = hdr.params[0].id;
4755
 
4856
         // Get the init value from the preheader's branch to header.
4957
         let init_val = match &func.block(ph_id).terminator {
50
-            Some(Terminator::Branch(dest, args)) if *dest == lp.header && args.len() == 1 =>
51
-                args[0],
58
+            Some(Terminator::Branch(dest, args)) if *dest == lp.header && args.len() == 1 => {
59
+                args[0]
60
+            }
5261
             _ => continue,
5362
         };
5463
 
5564
         // Init must be a compile-time constant.
56
-        let Some(init_const) = resolve_const_int(func, init_val) else { continue };
65
+        let Some(init_const) = resolve_const_int(func, init_val) else {
66
+            continue;
67
+        };
5768
 
5869
         // Must have a single latch.
59
-        if lp.latches.len() != 1 { continue; }
70
+        if lp.latches.len() != 1 {
71
+            continue;
72
+        }
6073
         let latch_id = lp.latches[0];
6174
 
6275
         // Latch must branch back to header with one arg.
6376
         let next_iv = match &func.block(latch_id).terminator {
64
-            Some(Terminator::Branch(dest, args)) if *dest == lp.header && args.len() == 1 =>
65
-                args[0],
77
+            Some(Terminator::Branch(dest, args)) if *dest == lp.header && args.len() == 1 => {
78
+                args[0]
79
+            }
6680
             _ => continue,
6781
         };
6882
 
@@ -72,8 +86,11 @@ fn peel_in_function(func: &mut Function) -> bool {
7286
             for inst in &func.block(latch_id).insts {
7387
                 if inst.id == next_iv {
7488
                     if let InstKind::IAdd(a, b) = &inst.kind {
75
-                        if *a == iv { found = resolve_const_int(func, *b); }
76
-                        else if *b == iv { found = resolve_const_int(func, *a); }
89
+                        if *a == iv {
90
+                            found = resolve_const_int(func, *b);
91
+                        } else if *b == iv {
92
+                            found = resolve_const_int(func, *a);
93
+                        }
7794
                     }
7895
                     break;
7996
                 }
@@ -116,19 +133,29 @@ fn has_first_iter_conditional(
116133
         for inst in &block.insts {
117134
             if let InstKind::ICmp(CmpOp::Eq, a, b) = &inst.kind {
118135
                 // One operand must be the IV.
119
-                let (is_iv, other) = if *a == iv { (true, *b) }
120
-                    else if *b == iv { (true, *a) }
121
-                    else { (false, ValueId(0)) };
122
-                if !is_iv { continue; }
136
+                let (is_iv, other) = if *a == iv {
137
+                    (true, *b)
138
+                } else if *b == iv {
139
+                    (true, *a)
140
+                } else {
141
+                    (false, ValueId(0))
142
+                };
143
+                if !is_iv {
144
+                    continue;
145
+                }
123146
 
124147
                 // The other operand must resolve to the init constant
125148
                 // and be loop-invariant.
126
-                if loop_defs.contains(&other) { continue; }
149
+                if loop_defs.contains(&other) {
150
+                    continue;
151
+                }
127152
                 if let Some(c) = resolve_const_int(func, other) {
128153
                     if c == init_const {
129154
                         // Must feed a CondBranch in this block.
130155
                         if let Some(Terminator::CondBranch { cond, .. }) = &block.terminator {
131
-                            if *cond == inst.id { return true; }
156
+                            if *cond == inst.id {
157
+                                return true;
158
+                            }
132159
                         }
133160
                     }
134161
                 }
@@ -152,10 +179,19 @@ fn find_loop_exit(func: &Function, lp: &crate::ir::walk::NaturalLoop) -> Option<
152179
 }
153180
 
154181
 /// Get the args passed to the exit block from the cmp's false-branch.
155
-fn find_exit_args(func: &Function, lp: &crate::ir::walk::NaturalLoop, exit_id: BlockId) -> Vec<ValueId> {
182
+fn find_exit_args(
183
+    func: &Function,
184
+    lp: &crate::ir::walk::NaturalLoop,
185
+    exit_id: BlockId,
186
+) -> Vec<ValueId> {
156187
     for &bid in &lp.body {
157188
         let block = func.block(bid);
158
-        if let Some(Terminator::CondBranch { false_dest, false_args, .. }) = &block.terminator {
189
+        if let Some(Terminator::CondBranch {
190
+            false_dest,
191
+            false_args,
192
+            ..
193
+        }) = &block.terminator
194
+        {
159195
             if *false_dest == exit_id {
160196
                 return false_args.clone();
161197
             }
@@ -186,7 +222,10 @@ fn do_peel(
186222
     // The IV type (needed to emit the init+stride constant).
187223
     let hdr = func.block(lp.header);
188224
     let iv_ty = hdr.params[0].ty.clone();
189
-    let iv_width = match &iv_ty { IrType::Int(w) => *w, _ => return };
225
+    let iv_width = match &iv_ty {
226
+        IrType::Int(w) => *w,
227
+        _ => return,
228
+    };
190229
     let init_const = resolve_const_int(func, init_val).unwrap();
191230
 
192231
     // Emit init+stride constant in a helper block so it's available.
@@ -247,8 +286,7 @@ fn do_peel(
247286
 
248287
     // --- Wire preheader → clone's header ---
249288
     let clone_header = block_map[&lp.header];
250
-    func.block_mut(ph_id).terminator =
251
-        Some(Terminator::Branch(clone_header, vec![init_val]));
289
+    func.block_mut(ph_id).terminator = Some(Terminator::Branch(clone_header, vec![init_val]));
252290
 }
253291
 
254292
 // ---------------------------------------------------------------------------
@@ -258,14 +296,18 @@ fn do_peel(
258296
 #[cfg(test)]
259297
 mod tests {
260298
     use super::*;
261
-    use crate::ir::types::{IrType, IntWidth};
262299
     use crate::ir::inst::*;
300
+    use crate::ir::types::{IntWidth, IrType};
301
+    use crate::lexer::{Position, Span};
263302
     use crate::opt::pass::Pass;
264
-    use crate::lexer::{Span, Position};
265303
 
266304
     fn span() -> Span {
267305
         let pos = Position { line: 0, col: 0 };
268
-        Span { file_id: 0, start: pos, end: pos }
306
+        Span {
307
+            file_id: 0,
308
+            start: pos,
309
+            end: pos,
310
+        }
269311
     }
270312
 
271313
     #[test]
@@ -295,45 +337,60 @@ mod tests {
295337
         let c1 = f.next_value_id();
296338
         f.register_type(c1, IrType::Int(IntWidth::I32));
297339
         f.block_mut(entry).insts.push(Inst {
298
-            id: c1, ty: IrType::Int(IntWidth::I32), span: span(),
340
+            id: c1,
341
+            ty: IrType::Int(IntWidth::I32),
342
+            span: span(),
299343
             kind: InstKind::ConstInt(1, IntWidth::I32),
300344
         });
301345
         let c10 = f.next_value_id();
302346
         f.register_type(c10, IrType::Int(IntWidth::I32));
303347
         f.block_mut(entry).insts.push(Inst {
304
-            id: c10, ty: IrType::Int(IntWidth::I32), span: span(),
348
+            id: c10,
349
+            ty: IrType::Int(IntWidth::I32),
350
+            span: span(),
305351
             kind: InstKind::ConstInt(10, IntWidth::I32),
306352
         });
307353
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![c1]));
308354
 
309355
         let iv = f.next_value_id();
310356
         f.register_type(iv, IrType::Int(IntWidth::I32));
311
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
357
+        f.block_mut(header).params.push(BlockParam {
358
+            id: iv,
359
+            ty: IrType::Int(IntWidth::I32),
360
+        });
312361
         f.block_mut(header).terminator = Some(Terminator::Branch(cmp, vec![]));
313362
 
314363
         let cmp_v = f.next_value_id();
315364
         f.register_type(cmp_v, IrType::Bool);
316365
         f.block_mut(cmp).insts.push(Inst {
317
-            id: cmp_v, ty: IrType::Bool, span: span(),
366
+            id: cmp_v,
367
+            ty: IrType::Bool,
368
+            span: span(),
318369
             kind: InstKind::ICmp(CmpOp::Le, iv, c10),
319370
         });
320371
         f.block_mut(cmp).terminator = Some(Terminator::CondBranch {
321372
             cond: cmp_v,
322
-            true_dest: body, true_args: vec![],
323
-            false_dest: exit, false_args: vec![],
373
+            true_dest: body,
374
+            true_args: vec![],
375
+            false_dest: exit,
376
+            false_args: vec![],
324377
         });
325378
 
326379
         // Body has NO equality check — just a store.
327380
         let alloca = f.next_value_id();
328381
         f.register_type(alloca, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
329382
         f.block_mut(body).insts.push(Inst {
330
-            id: alloca, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
383
+            id: alloca,
384
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
385
+            span: span(),
331386
             kind: InstKind::Alloca(IrType::Int(IntWidth::I32)),
332387
         });
333388
         let store_id = f.next_value_id();
334389
         f.register_type(store_id, IrType::Void);
335390
         f.block_mut(body).insts.push(Inst {
336
-            id: store_id, ty: IrType::Void, span: span(),
391
+            id: store_id,
392
+            ty: IrType::Void,
393
+            span: span(),
337394
             kind: InstKind::Store(iv, alloca),
338395
         });
339396
         f.block_mut(body).terminator = Some(Terminator::Branch(latch, vec![]));
@@ -341,7 +398,9 @@ mod tests {
341398
         let nxt = f.next_value_id();
342399
         f.register_type(nxt, IrType::Int(IntWidth::I32));
343400
         f.block_mut(latch).insts.push(Inst {
344
-            id: nxt, ty: IrType::Int(IntWidth::I32), span: span(),
401
+            id: nxt,
402
+            ty: IrType::Int(IntWidth::I32),
403
+            span: span(),
345404
             kind: InstKind::IAdd(iv, c1),
346405
         });
347406
         f.block_mut(latch).terminator = Some(Terminator::Branch(header, vec![nxt]));
src/opt/pipeline.rsmodified
104 lines changed — click to load
@@ -4,35 +4,35 @@
44
 //! configured `PassManager`. Adding a new pass to a level is a one-line
55
 //! change here, which keeps the dispatch logic in one place.
66
 
7
-use super::pass::PassManager;
7
+use super::bce::Bce;
8
+use super::call_resolve::CallResolve;
9
+use super::const_arg::ConstArgSpecialize;
810
 use super::const_fold::ConstFold;
911
 use super::const_prop::ConstProp;
10
-use super::dce::Dce;
1112
 use super::cse::LocalCse;
12
-use super::strength_reduce::StrengthReduce;
13
-use super::licm::Licm;
14
-use super::mem2reg::Mem2Reg;
13
+use super::dce::Dce;
14
+use super::dead_arg::DeadArgElim;
15
+use super::dead_func::DeadFuncElim;
1516
 use super::dse::Dse;
16
-use super::lsf::LocalLsf;
17
-use super::unroll::LoopUnroll;
18
-use super::preheader::PreheaderInsert;
19
-use super::unswitch::LoopUnswitch;
17
+use super::fast_math::FastMathReassoc;
18
+use super::fission::LoopFission;
19
+use super::fusion::LoopFusion;
20
+use super::global_lsf::GlobalLsf;
21
+use super::gvn::Gvn;
22
+use super::inline::Inline;
2023
 use super::interchange::LoopInterchange;
24
+use super::licm::Licm;
25
+use super::lsf::LocalLsf;
26
+use super::mem2reg::Mem2Reg;
27
+use super::pass::PassManager;
2128
 use super::peel::LoopPeel;
22
-use super::call_resolve::CallResolve;
23
-use super::inline::Inline;
24
-use super::simplify_cfg::SimplifyCfg;
25
-use super::dead_func::DeadFuncElim;
26
-use super::dead_arg::DeadArgElim;
27
-use super::const_arg::ConstArgSpecialize;
29
+use super::preheader::PreheaderInsert;
2830
 use super::return_prop::ReturnPropagate;
29
-use super::fast_math::FastMathReassoc;
31
+use super::simplify_cfg::SimplifyCfg;
3032
 use super::sroa::Sroa;
31
-use super::gvn::Gvn;
32
-use super::global_lsf::GlobalLsf;
33
-use super::bce::Bce;
34
-use super::fission::LoopFission;
35
-use super::fusion::LoopFusion;
33
+use super::strength_reduce::StrengthReduce;
34
+use super::unroll::LoopUnroll;
35
+use super::unswitch::LoopUnswitch;
3636
 use super::vectorize::Vectorize;
3737
 
3838
 /// Compiler optimization levels.
@@ -90,7 +90,10 @@ impl OptLevel {
9090
     /// builder below will gate registration on this. Same for the
9191
     /// other two predicates.
9292
     pub fn inlining(self) -> bool {
93
-        matches!(self, Self::O1 | Self::O2 | Self::O3 | Self::Os | Self::Ofast)
93
+        matches!(
94
+            self,
95
+            Self::O1 | Self::O2 | Self::O3 | Self::Os | Self::Ofast
96
+        )
9497
     }
9598
 
9699
     /// Does this level enable loop vectorization (NEON)?
@@ -145,7 +148,7 @@ pub fn build_pipeline(level: OptLevel) -> PassManager {
145148
             pm.add(Box::new(CallResolve));
146149
             pm.add(Box::new(Mem2Reg));
147150
             pm.add(Box::new(ConstFold));
148
-            pm.add(Box::new(Sroa));    // after SSA + const fold (GCC pattern)
151
+            pm.add(Box::new(Sroa)); // after SSA + const fold (GCC pattern)
149152
             pm.add(Box::new(Mem2Reg)); // re-promote SROA-created scalar allocas
150153
             pm.add(Box::new(Inline::for_level(OptLevel::O2)));
151154
             pm.add(Box::new(ConstArgSpecialize));
@@ -168,7 +171,7 @@ pub fn build_pipeline(level: OptLevel) -> PassManager {
168171
             pm.add(Box::new(LoopFission));
169172
             pm.add(Box::new(LoopFusion));
170173
             pm.add(Box::new(LoopUnroll));
171
-            pm.add(Box::new(Gvn));  // after loop passes to avoid SSA conflicts
174
+            pm.add(Box::new(Gvn)); // after loop passes to avoid SSA conflicts
172175
             pm.add(Box::new(Dce));
173176
         }
174177
         OptLevel::Os => {
@@ -314,9 +317,19 @@ mod tests {
314317
     fn pipelines_build() {
315318
         // O0 has no passes; every other level has at least one.
316319
         assert!(build_pipeline(OptLevel::O0).is_empty());
317
-        for lvl in [OptLevel::O1, OptLevel::O2, OptLevel::O3, OptLevel::Os, OptLevel::Ofast] {
320
+        for lvl in [
321
+            OptLevel::O1,
322
+            OptLevel::O2,
323
+            OptLevel::O3,
324
+            OptLevel::Os,
325
+            OptLevel::Ofast,
326
+        ] {
318327
             let pm = build_pipeline(lvl);
319
-            assert!(!pm.is_empty(), "pipeline {:?} should have at least one pass", lvl);
328
+            assert!(
329
+                !pm.is_empty(),
330
+                "pipeline {:?} should have at least one pass",
331
+                lvl
332
+            );
320333
         }
321334
     }
322335
 
src/opt/preheader.rsmodified
234 lines changed — click to load
@@ -7,21 +7,25 @@
77
 //! Run early at O2+ so downstream passes (LICM, unswitching, interchange)
88
 //! can assume every loop has a preheader.
99
 
10
-use crate::ir::inst::*;
11
-use crate::ir::walk::{find_natural_loops, predecessors};
1210
 use super::loop_utils::find_preheader;
1311
 use super::pass::Pass;
12
+use crate::ir::inst::*;
13
+use crate::ir::walk::{find_natural_loops, predecessors};
1414
 
1515
 /// Preheader insertion pass.
1616
 pub struct PreheaderInsert;
1717
 
1818
 impl Pass for PreheaderInsert {
19
-    fn name(&self) -> &'static str { "preheader-insert" }
19
+    fn name(&self) -> &'static str {
20
+        "preheader-insert"
21
+    }
2022
 
2123
     fn run(&self, module: &mut Module) -> bool {
2224
         let mut changed = false;
2325
         for func in &mut module.functions {
24
-            if insert_preheaders(func) { changed = true; }
26
+            if insert_preheaders(func) {
27
+                changed = true;
28
+            }
2529
         }
2630
         changed
2731
     }
@@ -47,14 +51,17 @@ fn insert_preheaders(func: &mut Function) -> bool {
4751
             Some(p) => p,
4852
             None => continue,
4953
         };
50
-        let mut outside: Vec<BlockId> = header_preds.iter()
54
+        let mut outside: Vec<BlockId> = header_preds
55
+            .iter()
5156
             .copied()
5257
             .filter(|p| !lp.body.contains(p))
5358
             .collect();
5459
         outside.sort_by_key(|b| b.0);
5560
         outside.dedup();
5661
 
57
-        if outside.is_empty() { continue; }
62
+        if outside.is_empty() {
63
+            continue;
64
+        }
5865
 
5966
         // Create the preheader block. It receives the same block params
6067
         // as the header and unconditionally branches to the header,
@@ -77,8 +84,7 @@ fn insert_preheaders(func: &mut Function) -> bool {
7784
 
7885
         // Preheader terminates with unconditional branch to header,
7986
         // passing its params through.
80
-        func.block_mut(ph_id).terminator =
81
-            Some(Terminator::Branch(lp.header, ph_param_ids));
87
+        func.block_mut(ph_id).terminator = Some(Terminator::Branch(lp.header, ph_param_ids));
8288
 
8389
         // Redirect each out-of-loop predecessor to branch to the
8490
         // preheader instead of the header.
@@ -103,16 +109,30 @@ fn redirect_terminator(func: &mut Function, block: BlockId, old_dest: BlockId, n
103109
     };
104110
     match term {
105111
         Terminator::Branch(dest, _) => {
106
-            if *dest == old_dest { *dest = new_dest; }
112
+            if *dest == old_dest {
113
+                *dest = new_dest;
114
+            }
107115
         }
108
-        Terminator::CondBranch { true_dest, false_dest, .. } => {
109
-            if *true_dest == old_dest { *true_dest = new_dest; }
110
-            if *false_dest == old_dest { *false_dest = new_dest; }
116
+        Terminator::CondBranch {
117
+            true_dest,
118
+            false_dest,
119
+            ..
120
+        } => {
121
+            if *true_dest == old_dest {
122
+                *true_dest = new_dest;
123
+            }
124
+            if *false_dest == old_dest {
125
+                *false_dest = new_dest;
126
+            }
111127
         }
112128
         Terminator::Switch { default, cases, .. } => {
113
-            if *default == old_dest { *default = new_dest; }
129
+            if *default == old_dest {
130
+                *default = new_dest;
131
+            }
114132
             for (_, dest) in cases.iter_mut() {
115
-                if *dest == old_dest { *dest = new_dest; }
133
+                if *dest == old_dest {
134
+                    *dest = new_dest;
135
+                }
116136
             }
117137
         }
118138
         _ => {}
@@ -126,13 +146,17 @@ fn redirect_terminator(func: &mut Function, block: BlockId, old_dest: BlockId, n
126146
 #[cfg(test)]
127147
 mod tests {
128148
     use super::*;
129
-    use crate::ir::types::{IrType, IntWidth};
149
+    use crate::ir::types::{IntWidth, IrType};
130150
     use crate::ir::walk::predecessors;
131
-    use crate::lexer::{Span, Position};
151
+    use crate::lexer::{Position, Span};
132152
 
133153
     fn span() -> Span {
134154
         let pos = Position { line: 0, col: 0 };
135
-        Span { file_id: 0, start: pos, end: pos }
155
+        Span {
156
+            file_id: 0,
157
+            start: pos,
158
+            end: pos,
159
+        }
136160
     }
137161
 
138162
     /// Build a function where the loop header has TWO out-of-loop
@@ -142,36 +166,44 @@ mod tests {
142166
         let mut f = Function::new("test".into(), vec![], IrType::Void);
143167
 
144168
         let header = f.create_block("header");
145
-        let body   = f.create_block("body");
146
-        let latch  = f.create_block("latch");
147
-        let exit   = f.create_block("exit");
148
-        let alt    = f.create_block("alt_entry");
149
-        let entry  = f.entry;
169
+        let body = f.create_block("body");
170
+        let latch = f.create_block("latch");
171
+        let exit = f.create_block("exit");
172
+        let alt = f.create_block("alt_entry");
173
+        let entry = f.entry;
150174
 
151175
         // Entry: const 1, condBr → header(1) or alt_entry
152176
         let c1 = f.next_value_id();
153177
         f.register_type(c1, IrType::Int(IntWidth::I32));
154178
         f.block_mut(entry).insts.push(Inst {
155
-            id: c1, ty: IrType::Int(IntWidth::I32), span: span(),
179
+            id: c1,
180
+            ty: IrType::Int(IntWidth::I32),
181
+            span: span(),
156182
             kind: InstKind::ConstInt(1, IntWidth::I32),
157183
         });
158184
         let cond = f.next_value_id();
159185
         f.register_type(cond, IrType::Bool);
160186
         f.block_mut(entry).insts.push(Inst {
161
-            id: cond, ty: IrType::Bool, span: span(),
187
+            id: cond,
188
+            ty: IrType::Bool,
189
+            span: span(),
162190
             kind: InstKind::ConstBool(true),
163191
         });
164192
         f.block_mut(entry).terminator = Some(Terminator::CondBranch {
165193
             cond,
166
-            true_dest: header, true_args: vec![c1],
167
-            false_dest: alt, false_args: vec![],
194
+            true_dest: header,
195
+            true_args: vec![c1],
196
+            false_dest: alt,
197
+            false_args: vec![],
168198
         });
169199
 
170200
         // Alt entry: const 5, br header(5)
171201
         let c5 = f.next_value_id();
172202
         f.register_type(c5, IrType::Int(IntWidth::I32));
173203
         f.block_mut(alt).insts.push(Inst {
174
-            id: c5, ty: IrType::Int(IntWidth::I32), span: span(),
204
+            id: c5,
205
+            ty: IrType::Int(IntWidth::I32),
206
+            span: span(),
175207
             kind: InstKind::ConstInt(5, IntWidth::I32),
176208
         });
177209
         f.block_mut(alt).terminator = Some(Terminator::Branch(header, vec![c5]));
@@ -180,24 +212,31 @@ mod tests {
180212
         let iv = f.next_value_id();
181213
         f.register_type(iv, IrType::Int(IntWidth::I32));
182214
         f.block_mut(header).params.push(BlockParam {
183
-            id: iv, ty: IrType::Int(IntWidth::I32),
215
+            id: iv,
216
+            ty: IrType::Int(IntWidth::I32),
184217
         });
185218
         let c10 = f.next_value_id();
186219
         f.register_type(c10, IrType::Int(IntWidth::I32));
187220
         f.block_mut(header).insts.push(Inst {
188
-            id: c10, ty: IrType::Int(IntWidth::I32), span: span(),
221
+            id: c10,
222
+            ty: IrType::Int(IntWidth::I32),
223
+            span: span(),
189224
             kind: InstKind::ConstInt(10, IntWidth::I32),
190225
         });
191226
         let cmp = f.next_value_id();
192227
         f.register_type(cmp, IrType::Bool);
193228
         f.block_mut(header).insts.push(Inst {
194
-            id: cmp, ty: IrType::Bool, span: span(),
229
+            id: cmp,
230
+            ty: IrType::Bool,
231
+            span: span(),
195232
             kind: InstKind::ICmp(CmpOp::Le, iv, c10),
196233
         });
197234
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
198235
             cond: cmp,
199
-            true_dest: body, true_args: vec![],
200
-            false_dest: exit, false_args: vec![],
236
+            true_dest: body,
237
+            true_args: vec![],
238
+            false_dest: exit,
239
+            false_args: vec![],
201240
         });
202241
 
203242
         // Body → latch
@@ -207,13 +246,17 @@ mod tests {
207246
         let one_l = f.next_value_id();
208247
         f.register_type(one_l, IrType::Int(IntWidth::I32));
209248
         f.block_mut(latch).insts.push(Inst {
210
-            id: one_l, ty: IrType::Int(IntWidth::I32), span: span(),
249
+            id: one_l,
250
+            ty: IrType::Int(IntWidth::I32),
251
+            span: span(),
211252
             kind: InstKind::ConstInt(1, IntWidth::I32),
212253
         });
213254
         let nxt = f.next_value_id();
214255
         f.register_type(nxt, IrType::Int(IntWidth::I32));
215256
         f.block_mut(latch).insts.push(Inst {
216
-            id: nxt, ty: IrType::Int(IntWidth::I32), span: span(),
257
+            id: nxt,
258
+            ty: IrType::Int(IntWidth::I32),
259
+            span: span(),
217260
             kind: InstKind::IAdd(iv, one_l),
218261
         });
219262
         f.block_mut(latch).terminator = Some(Terminator::Branch(header, vec![nxt]));
@@ -234,8 +277,10 @@ mod tests {
234277
         let loops = find_natural_loops(f);
235278
         let preds = predecessors(f);
236279
         assert_eq!(loops.len(), 1);
237
-        assert!(find_preheader(f, &loops[0], &preds).is_none(),
238
-            "should have no preheader before insertion");
280
+        assert!(
281
+            find_preheader(f, &loops[0], &preds).is_none(),
282
+            "should have no preheader before insertion"
283
+        );
239284
 
240285
         let pass = PreheaderInsert;
241286
         let changed = pass.run(&mut m);
src/opt/return_prop.rsmodified
169 lines changed — click to load
@@ -17,7 +17,9 @@ use super::util::substitute_uses;
1717
 pub struct ReturnPropagate;
1818
 
1919
 impl Pass for ReturnPropagate {
20
-    fn name(&self) -> &'static str { "return-prop" }
20
+    fn name(&self) -> &'static str {
21
+        "return-prop"
22
+    }
2123
 
2224
     fn run(&self, module: &mut Module) -> bool {
2325
         let plans = collect_plans(module);
@@ -101,11 +103,19 @@ fn const_value_of(func: &Function, value: ValueId) -> Option<ScalarConst> {
101103
 }
102104
 
103105
 fn side_effect_free(kind: &InstKind) -> bool {
104
-    !matches!(kind, InstKind::Store(..) | InstKind::Call(..) | InstKind::RuntimeCall(..))
106
+    !matches!(
107
+        kind,
108
+        InstKind::Store(..) | InstKind::Call(..) | InstKind::RuntimeCall(..)
109
+    )
105110
 }
106111
 
107112
 fn classify_return_source(func: &Function, value: ValueId) -> Option<ReturnSource> {
108
-    if let Some((idx, param)) = func.params.iter().enumerate().find(|(_, param)| param.id == value) {
113
+    if let Some((idx, param)) = func
114
+        .params
115
+        .iter()
116
+        .enumerate()
117
+        .find(|(_, param)| param.id == value)
118
+    {
109119
         if !param.ty.is_ptr() && is_scalar_type(&param.ty) {
110120
             return Some(ReturnSource::Param(idx));
111121
         }
@@ -115,7 +125,11 @@ fn classify_return_source(func: &Function, value: ValueId) -> Option<ReturnSourc
115125
     let inst = defs.get(&value)?;
116126
     match inst.kind {
117127
         InstKind::Load(addr) => {
118
-            let (idx, param) = func.params.iter().enumerate().find(|(_, param)| param.id == addr)?;
128
+            let (idx, param) = func
129
+                .params
130
+                .iter()
131
+                .enumerate()
132
+                .find(|(_, param)| param.id == addr)?;
119133
             let IrType::Ptr(inner) = &param.ty else {
120134
                 return None;
121135
             };
@@ -135,7 +149,12 @@ fn collect_plans(module: &Module) -> Vec<Option<ReturnSource>> {
135149
         if !func.internal_only || matches!(func.return_type, IrType::Void) {
136150
             continue;
137151
         }
138
-        if func.blocks.iter().flat_map(|block| block.insts.iter()).any(|inst| !side_effect_free(&inst.kind)) {
152
+        if func
153
+            .blocks
154
+            .iter()
155
+            .flat_map(|block| block.insts.iter())
156
+            .any(|inst| !side_effect_free(&inst.kind))
157
+        {
139158
             continue;
140159
         }
141160
 
@@ -211,7 +230,11 @@ fn default_span(func: &Function) -> Span {
211230
         span
212231
     } else {
213232
         let pos = Position { line: 0, col: 0 };
214
-        Span { file_id: 0, start: pos, end: pos }
233
+        Span {
234
+            file_id: 0,
235
+            start: pos,
236
+            end: pos,
237
+        }
215238
     }
216239
 }
217240
 
@@ -279,11 +302,10 @@ fn rewrite_caller(module: &mut Module, caller_idx: usize, plans: &[Option<Return
279302
     for (call_id, args, plan) in scheduled {
280303
         let replacement = match plan {
281304
             ReturnSource::Param(param_idx) => args.get(param_idx).copied(),
282
-            ReturnSource::LoadParam(param_idx) => {
283
-                args.get(param_idx)
284
-                    .copied()
285
-                    .and_then(|ptr| wrapper_value_for_call(caller, ptr, call_id))
286
-            }
305
+            ReturnSource::LoadParam(param_idx) => args
306
+                .get(param_idx)
307
+                .copied()
308
+                .and_then(|ptr| wrapper_value_for_call(caller, ptr, call_id)),
287309
             ReturnSource::Const(value) => Some(ensure_const_in_entry(caller, &mut cache, value)),
288310
         };
289311
         let Some(replacement) = replacement else {
@@ -327,13 +349,22 @@ mod tests {
327349
 
328350
     fn span() -> Span {
329351
         let pos = Position { line: 0, col: 0 };
330
-        Span { file_id: 0, start: pos, end: pos }
352
+        Span {
353
+            file_id: 0,
354
+            start: pos,
355
+            end: pos,
356
+        }
331357
     }
332358
 
333359
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
334360
         let id = f.next_value_id();
335361
         let entry = f.entry;
336
-        f.block_mut(entry).insts.push(Inst { id, kind, ty: ty.clone(), span: span() });
362
+        f.block_mut(entry).insts.push(Inst {
363
+            id,
364
+            kind,
365
+            ty: ty.clone(),
366
+            span: span(),
367
+        });
337368
         f.register_type(id, ty);
338369
         id
339370
     }
@@ -350,13 +381,21 @@ mod tests {
350381
         }];
351382
         let mut callee = Function::new("passthrough".into(), params, IrType::Int(IntWidth::I32));
352383
         callee.internal_only = true;
353
-        let loaded = push(&mut callee, InstKind::Load(ValueId(0)), IrType::Int(IntWidth::I32));
384
+        let loaded = push(
385
+            &mut callee,
386
+            InstKind::Load(ValueId(0)),
387
+            IrType::Int(IntWidth::I32),
388
+        );
354389
         let callee_entry = callee.entry;
355390
         callee.block_mut(callee_entry).terminator = Some(Terminator::Return(Some(loaded)));
356391
         module.add_function(callee);
357392
 
358393
         let mut caller = Function::new("main".into(), vec![], IrType::Int(IntWidth::I32));
359
-        let c7 = push(&mut caller, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
394
+        let c7 = push(
395
+            &mut caller,
396
+            InstKind::ConstInt(7, IntWidth::I32),
397
+            IrType::Int(IntWidth::I32),
398
+        );
360399
         let slot = push(
361400
             &mut caller,
362401
             InstKind::Alloca(IrType::Int(IntWidth::I32)),
@@ -375,7 +414,9 @@ mod tests {
375414
         assert!(ReturnPropagate.run(&mut module));
376415
         let caller_insts = &module.functions[1].blocks[0].insts;
377416
         assert!(
378
-            !caller_insts.iter().any(|inst| matches!(inst.kind, InstKind::Call(..))),
417
+            !caller_insts
418
+                .iter()
419
+                .any(|inst| matches!(inst.kind, InstKind::Call(..))),
379420
             "call should be removed after return propagation"
380421
         );
381422
         assert!(
@@ -390,7 +431,11 @@ mod tests {
390431
 
391432
         let mut callee = Function::new("const_fn".into(), vec![], IrType::Int(IntWidth::I32));
392433
         callee.internal_only = true;
393
-        let c42 = push(&mut callee, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
434
+        let c42 = push(
435
+            &mut callee,
436
+            InstKind::ConstInt(42, IntWidth::I32),
437
+            IrType::Int(IntWidth::I32),
438
+        );
394439
         let callee_entry = callee.entry;
395440
         callee.block_mut(callee_entry).terminator = Some(Terminator::Return(Some(c42)));
396441
         module.add_function(callee);
@@ -408,11 +453,15 @@ mod tests {
408453
         assert!(ReturnPropagate.run(&mut module));
409454
         let caller_insts = &module.functions[1].blocks[0].insts;
410455
         assert!(
411
-            !caller_insts.iter().any(|inst| matches!(inst.kind, InstKind::Call(..))),
456
+            !caller_insts
457
+                .iter()
458
+                .any(|inst| matches!(inst.kind, InstKind::Call(..))),
412459
             "constant helper call should be removed"
413460
         );
414461
         assert!(
415
-            caller_insts.iter().any(|inst| matches!(inst.kind, InstKind::ConstInt(42, IntWidth::I32))),
462
+            caller_insts
463
+                .iter()
464
+                .any(|inst| matches!(inst.kind, InstKind::ConstInt(42, IntWidth::I32))),
416465
             "caller should materialize the propagated constant"
417466
         );
418467
     }
src/opt/simplify_cfg.rsmodified
149 lines changed — click to load
@@ -16,19 +16,23 @@
1616
 //!
1717
 //! This eliminates the empty block chains left by inlining.
1818
 
19
+use super::pass::Pass;
1920
 use crate::ir::inst::*;
2021
 use crate::ir::walk::predecessors;
21
-use super::pass::Pass;
2222
 
2323
 pub struct SimplifyCfg;
2424
 
2525
 impl Pass for SimplifyCfg {
26
-    fn name(&self) -> &'static str { "simplify-cfg" }
26
+    fn name(&self) -> &'static str {
27
+        "simplify-cfg"
28
+    }
2729
 
2830
     fn run(&self, module: &mut Module) -> bool {
2931
         let mut changed = false;
3032
         for func in &mut module.functions {
31
-            if simplify_function(func) { changed = true; }
33
+            if simplify_function(func) {
34
+                changed = true;
35
+            }
3236
         }
3337
         changed
3438
     }
@@ -44,9 +48,15 @@ fn simplify_function(func: &mut Function) -> bool {
4448
         let mut redirect: Option<(BlockId, BlockId)> = None;
4549
 
4650
         for block in &func.blocks {
47
-            if block.id == func.entry { continue; }
48
-            if !block.insts.is_empty() { continue; }
49
-            if !block.params.is_empty() { continue; }
51
+            if block.id == func.entry {
52
+                continue;
53
+            }
54
+            if !block.insts.is_empty() {
55
+                continue;
56
+            }
57
+            if !block.params.is_empty() {
58
+                continue;
59
+            }
5060
             if let Some(Terminator::Branch(target, args)) = &block.terminator {
5161
                 if args.is_empty() {
5262
                     // This block is empty and just forwards to target.
@@ -56,11 +66,15 @@ fn simplify_function(func: &mut Function) -> bool {
5666
             }
5767
         }
5868
 
59
-        let Some((empty_block, target)) = redirect else { break };
69
+        let Some((empty_block, target)) = redirect else {
70
+            break;
71
+        };
6072
 
6173
         // Redirect all predecessors of empty_block to target instead.
6274
         for block in &mut func.blocks {
63
-            if block.id == empty_block { continue; } // don't redirect self
75
+            if block.id == empty_block {
76
+                continue;
77
+            } // don't redirect self
6478
             let term = match &mut block.terminator {
6579
                 Some(t) => t,
6680
                 None => continue,
@@ -97,7 +111,9 @@ fn simplify_function(func: &mut Function) -> bool {
97111
             }
98112
         }
99113
 
100
-        let Some((pred_id, succ_id)) = merge else { break };
114
+        let Some((pred_id, succ_id)) = merge else {
115
+            break;
116
+        };
101117
 
102118
         // Merge: append successor's instructions and terminator to predecessor.
103119
         let succ_insts = func.block(succ_id).insts.clone();
@@ -124,16 +140,30 @@ fn simplify_function(func: &mut Function) -> bool {
124140
 fn redirect_terminator(term: &mut Terminator, old: BlockId, new: BlockId) {
125141
     match term {
126142
         Terminator::Branch(dest, _) => {
127
-            if *dest == old { *dest = new; }
143
+            if *dest == old {
144
+                *dest = new;
145
+            }
128146
         }
129
-        Terminator::CondBranch { true_dest, false_dest, .. } => {
130
-            if *true_dest == old { *true_dest = new; }
131
-            if *false_dest == old { *false_dest = new; }
147
+        Terminator::CondBranch {
148
+            true_dest,
149
+            false_dest,
150
+            ..
151
+        } => {
152
+            if *true_dest == old {
153
+                *true_dest = new;
154
+            }
155
+            if *false_dest == old {
156
+                *false_dest = new;
157
+            }
132158
         }
133159
         Terminator::Switch { default, cases, .. } => {
134
-            if *default == old { *default = new; }
160
+            if *default == old {
161
+                *default = new;
162
+            }
135163
             for (_, dest) in cases.iter_mut() {
136
-                if *dest == old { *dest = new; }
164
+                if *dest == old {
165
+                    *dest = new;
166
+                }
137167
             }
138168
         }
139169
         _ => {}
@@ -143,7 +173,7 @@ fn redirect_terminator(term: &mut Terminator, old: BlockId, new: BlockId) {
143173
 #[cfg(test)]
144174
 mod tests {
145175
     use super::*;
146
-    use crate::ir::types::{IrType, IntWidth};
176
+    use crate::ir::types::{IntWidth, IrType};
147177
     use crate::opt::pass::Pass;
148178
 
149179
     #[test]
@@ -166,7 +196,11 @@ mod tests {
166196
         // contain the ret directly).
167197
         let f = &m.functions[0];
168198
         // The chain should be collapsed.
169
-        assert!(f.blocks.len() <= 2, "should merge empty chain, got {} blocks", f.blocks.len());
199
+        assert!(
200
+            f.blocks.len() <= 2,
201
+            "should merge empty chain, got {} blocks",
202
+            f.blocks.len()
203
+        );
170204
     }
171205
 
172206
     #[test]
@@ -179,7 +213,8 @@ mod tests {
179213
         let id = f.next_value_id();
180214
         f.register_type(id, IrType::Int(IntWidth::I32));
181215
         f.block_mut(b).insts.push(Inst {
182
-            id, ty: IrType::Int(IntWidth::I32),
216
+            id,
217
+            ty: IrType::Int(IntWidth::I32),
183218
             span: crate::lexer::Span {
184219
                 file_id: 0,
185220
                 start: crate::lexer::Position { line: 0, col: 0 },
@@ -195,8 +230,11 @@ mod tests {
195230
         // Body block may be merged into entry (single pred + unconditional branch).
196231
         // But the instruction should be preserved.
197232
         let f = &m.functions[0];
198
-        let has_const = f.blocks.iter().any(|bl|
199
-            bl.insts.iter().any(|i| matches!(i.kind, InstKind::ConstInt(42, _))));
233
+        let has_const = f.blocks.iter().any(|bl| {
234
+            bl.insts
235
+                .iter()
236
+                .any(|i| matches!(i.kind, InstKind::ConstInt(42, _)))
237
+        });
200238
         assert!(has_const, "const instruction must be preserved");
201239
     }
202240
 }
src/opt/sroa.rsmodified
185 lines changed — click to load
@@ -11,24 +11,28 @@
1111
 //!
1212
 //! After SROA, a second Mem2Reg pass promotes the new scalar allocas.
1313
 
14
-use std::collections::HashMap;
14
+use super::loop_utils::resolve_const_int;
15
+use super::pass::Pass;
1516
 use crate::ir::inst::*;
1617
 use crate::ir::types::IrType;
1718
 use crate::ir::walk::inst_uses;
18
-use super::loop_utils::resolve_const_int;
19
-use super::pass::Pass;
19
+use std::collections::HashMap;
2020
 
2121
 const SROA_MAX_FIELDS: u64 = 8;
2222
 
2323
 pub struct Sroa;
2424
 
2525
 impl Pass for Sroa {
26
-    fn name(&self) -> &'static str { "sroa" }
26
+    fn name(&self) -> &'static str {
27
+        "sroa"
28
+    }
2729
 
2830
     fn run(&self, module: &mut Module) -> bool {
2931
         let mut changed = false;
3032
         for func in &mut module.functions {
31
-            if sroa_function(func) { changed = true; }
33
+            if sroa_function(func) {
34
+                changed = true;
35
+            }
3236
         }
3337
         changed
3438
     }
@@ -37,7 +41,9 @@ impl Pass for Sroa {
3741
 fn sroa_function(func: &mut Function) -> bool {
3842
     // Collect candidate allocas: Array type, small, all constant-index GEPs.
3943
     let candidates = find_candidates(func);
40
-    if candidates.is_empty() { return false; }
44
+    if candidates.is_empty() {
45
+        return false;
46
+    }
4147
 
4248
     let mut changed = false;
4349
     for cand in candidates {
@@ -85,14 +91,18 @@ fn is_eligible(func: &Function, alloca_id: ValueId) -> bool {
8591
     for block in &func.blocks {
8692
         for inst in &block.insts {
8793
             let uses = inst_uses(&inst.kind);
88
-            if !uses.contains(&alloca_id) { continue; }
94
+            if !uses.contains(&alloca_id) {
95
+                continue;
96
+            }
8997
 
9098
             // Classify this use of the alloca.
9199
             match &inst.kind {
92100
                 // GEP with the alloca as base: OK if single constant index
93101
                 // AND the result type matches the element type (not byte-level).
94102
                 InstKind::GetElementPtr(base, indices) if *base == alloca_id => {
95
-                    if indices.len() != 1 { return false; }
103
+                    if indices.len() != 1 {
104
+                        return false;
105
+                    }
96106
                     if resolve_const_int(func, indices[0]).is_none() {
97107
                         return false;
98108
                     }
@@ -150,8 +160,16 @@ fn gep_result_escapes(func: &Function, gep_id: ValueId) -> bool {
150160
             match term {
151161
                 Terminator::Return(Some(v)) if *v == gep_id => return true,
152162
                 Terminator::Branch(_, args) if args.contains(&gep_id) => return true,
153
-                Terminator::CondBranch { cond, true_args, false_args, .. } => {
154
-                    if *cond == gep_id || true_args.contains(&gep_id) || false_args.contains(&gep_id) {
163
+                Terminator::CondBranch {
164
+                    cond,
165
+                    true_args,
166
+                    false_args,
167
+                    ..
168
+                } => {
169
+                    if *cond == gep_id
170
+                        || true_args.contains(&gep_id)
171
+                        || false_args.contains(&gep_id)
172
+                    {
155173
                         return true;
156174
                     }
157175
                 }
@@ -180,12 +198,15 @@ fn decompose_alloca(func: &mut Function, cand: &SroaCandidate) -> bool {
180198
         let new_id = func.next_value_id();
181199
         let ptr_ty = IrType::Ptr(Box::new(cand.elem_ty.clone()));
182200
         func.register_type(new_id, ptr_ty.clone());
183
-        func.block_mut(cand.alloca_block).insts.insert(insert_pos + i as usize, Inst {
184
-            id: new_id,
185
-            kind: InstKind::Alloca(cand.elem_ty.clone()),
186
-            ty: ptr_ty,
187
-            span,
188
-        });
201
+        func.block_mut(cand.alloca_block).insts.insert(
202
+            insert_pos + i as usize,
203
+            Inst {
204
+                id: new_id,
205
+                kind: InstKind::Alloca(cand.elem_ty.clone()),
206
+                ty: ptr_ty,
207
+                span,
208
+            },
209
+        );
189210
         field_allocas.push(new_id);
190211
     }
191212
 
@@ -207,7 +228,9 @@ fn decompose_alloca(func: &mut Function, cand: &SroaCandidate) -> bool {
207228
         }
208229
     }
209230
 
210
-    if gep_to_field.is_empty() { return false; }
231
+    if gep_to_field.is_empty() {
232
+        return false;
233
+    }
211234
 
212235
     // Rewrite all uses of GEP results to use the field allocas.
213236
     for block in &mut func.blocks {
@@ -243,12 +266,16 @@ fn decompose_alloca(func: &mut Function, cand: &SroaCandidate) -> bool {
243266
 mod tests {
244267
     use super::*;
245268
     use crate::ir::types::IntWidth;
269
+    use crate::lexer::{Position, Span};
246270
     use crate::opt::pass::Pass;
247
-    use crate::lexer::{Span, Position};
248271
 
249272
     fn span() -> Span {
250273
         let pos = Position { line: 0, col: 0 };
251
-        Span { file_id: 0, start: pos, end: pos }
274
+        Span {
275
+            file_id: 0,
276
+            start: pos,
277
+            end: pos,
278
+        }
252279
     }
253280
 
254281
     #[test]
@@ -258,7 +285,9 @@ mod tests {
258285
         let a = f.next_value_id();
259286
         f.register_type(a, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
260287
         f.block_mut(f.entry).insts.push(Inst {
261
-            id: a, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))), span: span(),
288
+            id: a,
289
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
290
+            span: span(),
262291
             kind: InstKind::Alloca(IrType::Int(IntWidth::I32)),
263292
         });
264293
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
@@ -297,7 +326,10 @@ mod tests {
297326
         });
298327
 
299328
         let gep = f.next_value_id();
300
-        f.register_type(gep, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))));
329
+        f.register_type(
330
+            gep,
331
+            IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))),
332
+        );
301333
         f.block_mut(f.entry).insts.push(Inst {
302334
             id: gep,
303335
             ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))),
@@ -306,12 +338,21 @@ mod tests {
306338
         });
307339
 
308340
         let sink = f.next_value_id();
309
-        f.register_type(sink, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))))));
341
+        f.register_type(
342
+            sink,
343
+            IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(
344
+                IrType::Int(IntWidth::I8),
345
+            )))))),
346
+        );
310347
         f.block_mut(f.entry).insts.push(Inst {
311348
             id: sink,
312
-            ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))))),
349
+            ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(
350
+                IrType::Int(IntWidth::I8),
351
+            )))))),
313352
             span: span(),
314
-            kind: InstKind::Alloca(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8)))))),
353
+            kind: InstKind::Alloca(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(
354
+                IntWidth::I8,
355
+            )))))),
315356
         });
316357
 
317358
         let escape_store = f.next_value_id();
@@ -326,6 +367,9 @@ mod tests {
326367
         f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
327368
         m.add_function(f);
328369
 
329
-        assert!(!Sroa.run(&mut m), "GEP addresses that escape should block SROA");
370
+        assert!(
371
+            !Sroa.run(&mut m),
372
+            "GEP addresses that escape should block SROA"
373
+        );
330374
     }
331375
 }
src/opt/strength_reduce.rsmodified
416 lines changed — click to load
@@ -46,7 +46,7 @@
4646
 use super::pass::Pass;
4747
 use super::util::{for_each_operand_mut, for_each_terminator_operand_mut};
4848
 use crate::ir::inst::*;
49
-use crate::ir::types::{IrType, IntWidth};
49
+use crate::ir::types::{IntWidth, IrType};
5050
 use std::collections::HashMap;
5151
 
5252
 /// Apply `rewrites` to every operand slot in the function in a
@@ -101,8 +101,9 @@ fn collect_int_consts(func: &Function) -> HashMap<ValueId, (i64, IntWidth)> {
101101
 /// Sign-extend a stored i64 to its declared bit width. Used so that
102102
 /// "is this -1?" checks survive narrow types.
103103
 fn sext(v: i64, bits: u32) -> i64 {
104
-    if bits >= 64 { v }
105
-    else {
104
+    if bits >= 64 {
105
+        v
106
+    } else {
106107
         let shift = 64 - bits;
107108
         (v << shift) >> shift
108109
     }
@@ -112,7 +113,9 @@ fn sext(v: i64, bits: u32) -> i64 {
112113
 /// when `v == 1 << k` and `k > 0`. (`v == 1` is handled separately as
113114
 /// "multiply by 1 → identity".)
114115
 fn pow2_exponent(v: i64) -> Option<u32> {
115
-    if v <= 0 { return None; }
116
+    if v <= 0 {
117
+        return None;
118
+    }
116119
     let u = v as u64;
117120
     if u.is_power_of_two() && u != 1 {
118121
         Some(u.trailing_zeros())
@@ -138,11 +141,12 @@ enum Rewrite {
138141
 
139142
 /// Try to derive a strength-reduction rewrite for one instruction.
140143
 /// Returns `None` if no rewrite applies.
141
-fn rewrite_for(
142
-    inst: &Inst,
143
-    consts: &HashMap<ValueId, (i64, IntWidth)>,
144
-) -> Option<Rewrite> {
145
-    let int_w = if let IrType::Int(w) = inst.ty { w } else { return None; };
144
+fn rewrite_for(inst: &Inst, consts: &HashMap<ValueId, (i64, IntWidth)>) -> Option<Rewrite> {
145
+    let int_w = if let IrType::Int(w) = inst.ty {
146
+        w
147
+    } else {
148
+        return None;
149
+    };
146150
     // Audit m4-1: after the M4-4 normalization in `collect_int_consts`,
147151
     // every `kv` returned from `const_int` is already sign-extended
148152
     // at its source width. The earlier code re-sext'd at `int_w` (the
@@ -168,7 +172,9 @@ fn rewrite_for(
168172
                     return Some(Rewrite::KindOnly(InstKind::ConstInt(0, int_w)));
169173
                 }
170174
                 if kv == 1 {
171
-                    return Some(Rewrite::Identity { pass_through: var_id });
175
+                    return Some(Rewrite::Identity {
176
+                        pass_through: var_id,
177
+                    });
172178
                 }
173179
                 if kv == -1 {
174180
                     return Some(Rewrite::KindOnly(InstKind::INeg(var_id)));
@@ -278,7 +284,9 @@ fn rewrite_for(
278284
 pub struct StrengthReduce;
279285
 
280286
 impl Pass for StrengthReduce {
281
-    fn name(&self) -> &'static str { "strength-reduce" }
287
+    fn name(&self) -> &'static str {
288
+        "strength-reduce"
289
+    }
282290
 
283291
     fn run(&self, module: &mut Module) -> bool {
284292
         let mut changed = false;
@@ -298,7 +306,9 @@ impl Pass for StrengthReduce {
298306
                     }
299307
                 }
300308
             }
301
-            if rewrites.is_empty() { continue; }
309
+            if rewrites.is_empty() {
310
+                continue;
311
+            }
302312
 
303313
             // Second pass: apply rewrites. We process them in reverse
304314
             // block-then-instruction order so that inserting a new
@@ -317,15 +327,22 @@ impl Pass for StrengthReduce {
317327
             for (bi, ii, rw, old_id, ty) in rewrites {
318328
                 match rw {
319329
                     Rewrite::ShlByConst { var, k } => {
320
-                        let int_w = if let IrType::Int(w) = ty { w } else { unreachable!() };
330
+                        let int_w = if let IrType::Int(w) = ty {
331
+                            w
332
+                        } else {
333
+                            unreachable!()
334
+                        };
321335
                         let kid = func.next_value_id();
322336
                         let span = func.blocks[bi].insts[ii].span;
323
-                        func.blocks[bi].insts.insert(ii, Inst {
324
-                            id: kid,
325
-                            kind: InstKind::ConstInt(k as i128, int_w),
326
-                            ty: IrType::Int(int_w),
327
-                            span,
328
-                        });
337
+                        func.blocks[bi].insts.insert(
338
+                            ii,
339
+                            Inst {
340
+                                id: kid,
341
+                                kind: InstKind::ConstInt(k as i128, int_w),
342
+                                ty: IrType::Int(int_w),
343
+                                span,
344
+                            },
345
+                        );
329346
                         // The original instruction shifted to ii+1.
330347
                         func.blocks[bi].insts[ii + 1].kind = InstKind::Shl(var, kid);
331348
                     }
@@ -376,7 +393,9 @@ impl Pass for StrengthReduce {
376393
                         std::collections::HashSet::new();
377394
                     visited.insert(k);
378395
                     while let Some(&next) = identity_rewrites.get(&cur) {
379
-                        if !visited.insert(next) { break; }
396
+                        if !visited.insert(next) {
397
+                            break;
398
+                        }
380399
                         cur = next;
381400
                     }
382401
                     identity_rewrites.insert(k, cur);
@@ -392,17 +411,26 @@ impl Pass for StrengthReduce {
392411
 mod tests {
393412
     use super::*;
394413
     use crate::ir::types::IrType;
395
-    use crate::lexer::{Span, Position};
414
+    use crate::lexer::{Position, Span};
396415
 
397416
     fn dummy_span() -> Span {
398417
         let p = Position { line: 1, col: 1 };
399
-        Span { start: p, end: p, file_id: 0 }
418
+        Span {
419
+            start: p,
420
+            end: p,
421
+            file_id: 0,
422
+        }
400423
     }
401424
 
402425
     fn push(f: &mut Function, kind: InstKind, ty: IrType) -> ValueId {
403426
         let id = f.next_value_id();
404427
         let entry = f.entry;
405
-        f.block_mut(entry).insts.push(Inst { id, kind, ty, span: dummy_span() });
428
+        f.block_mut(entry).insts.push(Inst {
429
+            id,
430
+            kind,
431
+            ty,
432
+            span: dummy_span(),
433
+        });
406434
         id
407435
     }
408436
 
@@ -415,8 +443,16 @@ mod tests {
415443
     #[test]
416444
     fn imul_by_pow2_becomes_shl() {
417445
         let (mut m, mut f) = make_fn();
418
-        let x = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
419
-        let k = push(&mut f, InstKind::ConstInt(8, IntWidth::I32), IrType::Int(IntWidth::I32));
446
+        let x = push(
447
+            &mut f,
448
+            InstKind::ConstInt(7, IntWidth::I32),
449
+            IrType::Int(IntWidth::I32),
450
+        );
451
+        let k = push(
452
+            &mut f,
453
+            InstKind::ConstInt(8, IntWidth::I32),
454
+            IrType::Int(IntWidth::I32),
455
+        );
420456
         let y = push(&mut f, InstKind::IMul(x, k), IrType::Int(IntWidth::I32));
421457
         let entry = f.entry;
422458
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -425,21 +461,37 @@ mod tests {
425461
         assert!(StrengthReduce.run(&mut m));
426462
         // The Shl should reference x and a freshly inserted const(3).
427463
         let block = &m.functions[0].blocks[0];
428
-        let shl = block.insts.iter().find_map(|i| match &i.kind {
429
-            InstKind::Shl(var, kid) => Some((*var, *kid)),
430
-            _ => None,
431
-        }).expect("expected Shl");
464
+        let shl = block
465
+            .insts
466
+            .iter()
467
+            .find_map(|i| match &i.kind {
468
+                InstKind::Shl(var, kid) => Some((*var, *kid)),
469
+                _ => None,
470
+            })
471
+            .expect("expected Shl");
432472
         assert_eq!(shl.0, x);
433473
         // The shift count should be a const(3).
434
-        let kconst = block.insts.iter().find(|i| i.id == shl.1).expect("shift const");
474
+        let kconst = block
475
+            .insts
476
+            .iter()
477
+            .find(|i| i.id == shl.1)
478
+            .expect("shift const");
435479
         assert!(matches!(kconst.kind, InstKind::ConstInt(3, IntWidth::I32)));
436480
     }
437481
 
438482
     #[test]
439483
     fn imul_by_zero_becomes_const_zero() {
440484
         let (mut m, mut f) = make_fn();
441
-        let x = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
442
-        let z = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
485
+        let x = push(
486
+            &mut f,
487
+            InstKind::ConstInt(7, IntWidth::I32),
488
+            IrType::Int(IntWidth::I32),
489
+        );
490
+        let z = push(
491
+            &mut f,
492
+            InstKind::ConstInt(0, IntWidth::I32),
493
+            IrType::Int(IntWidth::I32),
494
+        );
443495
         let y = push(&mut f, InstKind::IMul(x, z), IrType::Int(IntWidth::I32));
444496
         let entry = f.entry;
445497
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -447,15 +499,27 @@ mod tests {
447499
 
448500
         assert!(StrengthReduce.run(&mut m));
449501
         // y now defines const(0)
450
-        let y_inst = m.functions[0].blocks[0].insts.iter().find(|i| i.id == y).unwrap();
502
+        let y_inst = m.functions[0].blocks[0]
503
+            .insts
504
+            .iter()
505
+            .find(|i| i.id == y)
506
+            .unwrap();
451507
         assert!(matches!(y_inst.kind, InstKind::ConstInt(0, IntWidth::I32)));
452508
     }
453509
 
454510
     #[test]
455511
     fn imul_by_one_becomes_identity() {
456512
         let (mut m, mut f) = make_fn();
457
-        let x = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
458
-        let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
513
+        let x = push(
514
+            &mut f,
515
+            InstKind::ConstInt(7, IntWidth::I32),
516
+            IrType::Int(IntWidth::I32),
517
+        );
518
+        let one = push(
519
+            &mut f,
520
+            InstKind::ConstInt(1, IntWidth::I32),
521
+            IrType::Int(IntWidth::I32),
522
+        );
459523
         let y = push(&mut f, InstKind::IMul(x, one), IrType::Int(IntWidth::I32));
460524
         let entry = f.entry;
461525
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -472,15 +536,27 @@ mod tests {
472536
     #[test]
473537
     fn imul_by_neg_one_becomes_neg() {
474538
         let (mut m, mut f) = make_fn();
475
-        let x = push(&mut f, InstKind::ConstInt(7, IntWidth::I32), IrType::Int(IntWidth::I32));
476
-        let neg = push(&mut f, InstKind::ConstInt(-1, IntWidth::I32), IrType::Int(IntWidth::I32));
539
+        let x = push(
540
+            &mut f,
541
+            InstKind::ConstInt(7, IntWidth::I32),
542
+            IrType::Int(IntWidth::I32),
543
+        );
544
+        let neg = push(
545
+            &mut f,
546
+            InstKind::ConstInt(-1, IntWidth::I32),
547
+            IrType::Int(IntWidth::I32),
548
+        );
477549
         let y = push(&mut f, InstKind::IMul(x, neg), IrType::Int(IntWidth::I32));
478550
         let entry = f.entry;
479551
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
480552
         m.add_function(f);
481553
 
482554
         assert!(StrengthReduce.run(&mut m));
483
-        let y_inst = m.functions[0].blocks[0].insts.iter().find(|i| i.id == y).unwrap();
555
+        let y_inst = m.functions[0].blocks[0]
556
+            .insts
557
+            .iter()
558
+            .find(|i| i.id == y)
559
+            .unwrap();
484560
         match y_inst.kind {
485561
             InstKind::INeg(v) => assert_eq!(v, x),
486562
             ref other => panic!("expected INeg, got {:?}", other),
@@ -490,8 +566,16 @@ mod tests {
490566
     #[test]
491567
     fn iadd_zero_becomes_identity() {
492568
         let (mut m, mut f) = make_fn();
493
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
494
-        let z = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
569
+        let x = push(
570
+            &mut f,
571
+            InstKind::ConstInt(42, IntWidth::I32),
572
+            IrType::Int(IntWidth::I32),
573
+        );
574
+        let z = push(
575
+            &mut f,
576
+            InstKind::ConstInt(0, IntWidth::I32),
577
+            IrType::Int(IntWidth::I32),
578
+        );
495579
         let y = push(&mut f, InstKind::IAdd(x, z), IrType::Int(IntWidth::I32));
496580
         let entry = f.entry;
497581
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -507,15 +591,27 @@ mod tests {
507591
     #[test]
508592
     fn isub_from_zero_becomes_neg() {
509593
         let (mut m, mut f) = make_fn();
510
-        let z = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
511
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
594
+        let z = push(
595
+            &mut f,
596
+            InstKind::ConstInt(0, IntWidth::I32),
597
+            IrType::Int(IntWidth::I32),
598
+        );
599
+        let x = push(
600
+            &mut f,
601
+            InstKind::ConstInt(42, IntWidth::I32),
602
+            IrType::Int(IntWidth::I32),
603
+        );
512604
         let y = push(&mut f, InstKind::ISub(z, x), IrType::Int(IntWidth::I32));
513605
         let entry = f.entry;
514606
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
515607
         m.add_function(f);
516608
 
517609
         assert!(StrengthReduce.run(&mut m));
518
-        let y_inst = m.functions[0].blocks[0].insts.iter().find(|i| i.id == y).unwrap();
610
+        let y_inst = m.functions[0].blocks[0]
611
+            .insts
612
+            .iter()
613
+            .find(|i| i.id == y)
614
+            .unwrap();
519615
         match y_inst.kind {
520616
             InstKind::INeg(v) => assert_eq!(v, x),
521617
             _ => panic!(),
@@ -525,8 +621,16 @@ mod tests {
525621
     #[test]
526622
     fn idiv_by_one_becomes_identity() {
527623
         let (mut m, mut f) = make_fn();
528
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
529
-        let one = push(&mut f, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
624
+        let x = push(
625
+            &mut f,
626
+            InstKind::ConstInt(42, IntWidth::I32),
627
+            IrType::Int(IntWidth::I32),
628
+        );
629
+        let one = push(
630
+            &mut f,
631
+            InstKind::ConstInt(1, IntWidth::I32),
632
+            IrType::Int(IntWidth::I32),
633
+        );
530634
         let y = push(&mut f, InstKind::IDiv(x, one), IrType::Int(IntWidth::I32));
531635
         let entry = f.entry;
532636
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -542,9 +646,21 @@ mod tests {
542646
     #[test]
543647
     fn band_with_neg_one_becomes_identity() {
544648
         let (mut m, mut f) = make_fn();
545
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
546
-        let mask = push(&mut f, InstKind::ConstInt(-1, IntWidth::I32), IrType::Int(IntWidth::I32));
547
-        let y = push(&mut f, InstKind::BitAnd(x, mask), IrType::Int(IntWidth::I32));
649
+        let x = push(
650
+            &mut f,
651
+            InstKind::ConstInt(42, IntWidth::I32),
652
+            IrType::Int(IntWidth::I32),
653
+        );
654
+        let mask = push(
655
+            &mut f,
656
+            InstKind::ConstInt(-1, IntWidth::I32),
657
+            IrType::Int(IntWidth::I32),
658
+        );
659
+        let y = push(
660
+            &mut f,
661
+            InstKind::BitAnd(x, mask),
662
+            IrType::Int(IntWidth::I32),
663
+        );
548664
         let entry = f.entry;
549665
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
550666
         m.add_function(f);
@@ -559,23 +675,43 @@ mod tests {
559675
     #[test]
560676
     fn band_with_zero_becomes_const_zero() {
561677
         let (mut m, mut f) = make_fn();
562
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
563
-        let z = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
678
+        let x = push(
679
+            &mut f,
680
+            InstKind::ConstInt(42, IntWidth::I32),
681
+            IrType::Int(IntWidth::I32),
682
+        );
683
+        let z = push(
684
+            &mut f,
685
+            InstKind::ConstInt(0, IntWidth::I32),
686
+            IrType::Int(IntWidth::I32),
687
+        );
564688
         let y = push(&mut f, InstKind::BitAnd(x, z), IrType::Int(IntWidth::I32));
565689
         let entry = f.entry;
566690
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
567691
         m.add_function(f);
568692
 
569693
         assert!(StrengthReduce.run(&mut m));
570
-        let y_inst = m.functions[0].blocks[0].insts.iter().find(|i| i.id == y).unwrap();
694
+        let y_inst = m.functions[0].blocks[0]
695
+            .insts
696
+            .iter()
697
+            .find(|i| i.id == y)
698
+            .unwrap();
571699
         assert!(matches!(y_inst.kind, InstKind::ConstInt(0, IntWidth::I32)));
572700
     }
573701
 
574702
     #[test]
575703
     fn shift_by_zero_becomes_identity() {
576704
         let (mut m, mut f) = make_fn();
577
-        let x = push(&mut f, InstKind::ConstInt(42, IntWidth::I32), IrType::Int(IntWidth::I32));
578
-        let z = push(&mut f, InstKind::ConstInt(0, IntWidth::I32), IrType::Int(IntWidth::I32));
705
+        let x = push(
706
+            &mut f,
707
+            InstKind::ConstInt(42, IntWidth::I32),
708
+            IrType::Int(IntWidth::I32),
709
+        );
710
+        let z = push(
711
+            &mut f,
712
+            InstKind::ConstInt(0, IntWidth::I32),
713
+            IrType::Int(IntWidth::I32),
714
+        );
579715
         let y = push(&mut f, InstKind::Shl(x, z), IrType::Int(IntWidth::I32));
580716
         let entry = f.entry;
581717
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
@@ -607,7 +743,11 @@ mod tests {
607743
             },
608744
         ];
609745
         let mut f = Function::new("f".into(), params, IrType::Int(IntWidth::I32));
610
-        let y = push(&mut f, InstKind::IMul(ValueId(0), ValueId(1)), IrType::Int(IntWidth::I32));
746
+        let y = push(
747
+            &mut f,
748
+            InstKind::IMul(ValueId(0), ValueId(1)),
749
+            IrType::Int(IntWidth::I32),
750
+        );
611751
         let entry = f.entry;
612752
         f.block_mut(entry).terminator = Some(Terminator::Return(Some(y)));
613753
         m.add_function(f);
src/opt/unroll.rsmodified
934 lines changed — click to load
@@ -58,14 +58,18 @@
5858
 use super::pass::Pass;
5959
 use super::util::{find_natural_loops, predecessors, NaturalLoop};
6060
 use crate::ir::inst::*;
61
-use crate::ir::types::{IrType, IntWidth};
61
+use crate::ir::types::{IntWidth, IrType};
6262
 use crate::ir::walk::prune_unreachable;
63
-use crate::lexer::{Span, Position};
63
+use crate::lexer::{Position, Span};
6464
 use std::collections::{HashMap, HashSet};
6565
 
6666
 fn dummy_span() -> Span {
6767
     let pos = Position { line: 0, col: 0 };
68
-    Span { file_id: 0, start: pos, end: pos }
68
+    Span {
69
+        file_id: 0,
70
+        start: pos,
71
+        end: pos,
72
+    }
6973
 }
7074
 
7175
 // ---------------------------------------------------------------------------
@@ -94,7 +98,9 @@ const BODY_SIZE_MAX: usize = 30;
9498
 pub struct LoopUnroll;
9599
 
96100
 impl Pass for LoopUnroll {
97
-    fn name(&self) -> &'static str { "loop-unroll" }
101
+    fn name(&self) -> &'static str {
102
+        "loop-unroll"
103
+    }
98104
 
99105
     fn run(&self, module: &mut Module) -> bool {
100106
         let mut changed = false;
@@ -135,23 +141,23 @@ fn unroll_in_function(func: &mut Function) -> bool {
135141
 
136142
 #[derive(Debug)]
137143
 struct LoopShape {
138
-    preheader:   BlockId,
139
-    header:      BlockId,   // block with IV block param; branches to cmp_block
140
-    cmp_block:   BlockId,   // block with icmp + condBr to body/exit
144
+    preheader: BlockId,
145
+    header: BlockId,    // block with IV block param; branches to cmp_block
146
+    cmp_block: BlockId, // block with icmp + condBr to body/exit
141147
     /// The computation blocks (everything that is not header, cmp_block, or
142148
     /// latch). Ordered in CFG traversal order from cmp_block's true-successor
143149
     /// to latch's predecessor. For most Fortran DO loops this is a single
144150
     /// block ("do_body"). Multi-block bodies are supported as long as the
145151
     /// sub-CFG is a linear chain with no branches to outside.
146152
     body_blocks: Vec<BlockId>,
147
-    latch:       BlockId,   // iadd IV, 1 + br header(IV_next)
148
-    exit:        BlockId,   // cond_br false target
149
-    iv_param:    ValueId,
150
-    iv_ty:       IrType,
151
-    iv_init:     i64,
152
-    iv_bound:    i64,       // inclusive upper bound
153
-    trip_count:  usize,
154
-    exit_args:   Vec<ValueId>, // args from cmp_block's false branch to exit
153
+    latch: BlockId, // iadd IV, 1 + br header(IV_next)
154
+    exit: BlockId,  // cond_br false target
155
+    iv_param: ValueId,
156
+    iv_ty: IrType,
157
+    iv_init: i64,
158
+    iv_bound: i64, // inclusive upper bound
159
+    trip_count: usize,
160
+    exit_args: Vec<ValueId>, // args from cmp_block's false branch to exit
155161
 }
156162
 
157163
 fn is_do_concurrent_loop(
@@ -178,37 +184,51 @@ fn detect_simple_loop(
178184
     preds: &HashMap<BlockId, Vec<BlockId>>,
179185
 ) -> Option<LoopShape> {
180186
     // ---- structural requirements ----------------------------------------
181
-    if nl.latches.len() != 1 { return None; }
187
+    if nl.latches.len() != 1 {
188
+        return None;
189
+    }
182190
     let latch = nl.latches[0];
183
-    if latch == nl.header { return None; }    // no self-loop
184
-    // Body must have between 2 (header+latch) and 5 (header+cmp+body×N+latch) blocks.
185
-    if nl.body.len() < 2 || nl.body.len() > 5 { return None; }
191
+    if latch == nl.header {
192
+        return None;
193
+    } // no self-loop
194
+      // Body must have between 2 (header+latch) and 5 (header+cmp+body×N+latch) blocks.
195
+    if nl.body.len() < 2 || nl.body.len() > 5 {
196
+        return None;
197
+    }
186198
 
187199
     let header = nl.header;
188200
 
189201
     // ---- header must have exactly 1 block param (the IV) ----------------
190202
     let hdr = func.block(header);
191
-    if hdr.params.len() != 1 { return None; }
203
+    if hdr.params.len() != 1 {
204
+        return None;
205
+    }
192206
     let iv_param = hdr.params[0].id;
193
-    let iv_ty    = hdr.params[0].ty.clone();
194
-    if !matches!(iv_ty, IrType::Int(_)) { return None; }
207
+    let iv_ty = hdr.params[0].ty.clone();
208
+    if !matches!(iv_ty, IrType::Int(_)) {
209
+        return None;
210
+    }
195211
 
196212
     // ---- find preheader -------------------------------------------------
197213
     let header_preds = preds.get(&header)?;
198
-    let mut outside: Vec<BlockId> = header_preds.iter()
214
+    let mut outside: Vec<BlockId> = header_preds
215
+        .iter()
199216
         .copied()
200217
         .filter(|p| !nl.body.contains(p))
201218
         .collect();
202219
     outside.sort_by_key(|b| b.0);
203220
     outside.dedup();
204
-    if outside.len() != 1 { return None; }
221
+    if outside.len() != 1 {
222
+        return None;
223
+    }
205224
     let preheader = outside[0];
206225
 
207226
     // Preheader must branch to header with exactly 1 arg (the initial IV).
208227
     let ph_blk = func.block(preheader);
209228
     let iv_init = match &ph_blk.terminator {
210
-        Some(Terminator::Branch(dest, args)) if *dest == header && args.len() == 1 =>
211
-            resolve_const_int(func, args[0])?,
229
+        Some(Terminator::Branch(dest, args)) if *dest == header && args.len() == 1 => {
230
+            resolve_const_int(func, args[0])?
231
+        }
212232
         _ => return None,
213233
     };
214234
 
@@ -229,21 +249,29 @@ fn detect_simple_loop(
229249
         } else {
230250
             // Case (b): header must be a transparent relay.
231251
             let hdr_blk = func.block(header);
232
-            if !hdr_blk.insts.is_empty() { return None; } // must have 0 instructions
252
+            if !hdr_blk.insts.is_empty() {
253
+                return None;
254
+            } // must have 0 instructions
233255
             let relay_target = match &hdr_blk.terminator {
234256
                 Some(Terminator::Branch(t, args)) if args.is_empty() => *t,
235257
                 _ => return None,
236258
             };
237
-            if !nl.body.contains(&relay_target) { return None; }
259
+            if !nl.body.contains(&relay_target) {
260
+                return None;
261
+            }
238262
             let (bound, ex, args) = detect_bound_and_exit(func, relay_target, iv_param)?;
239263
             (relay_target, bound, ex, args)
240264
         }
241265
     };
242266
 
243
-    if nl.body.contains(&exit) { return None; }
267
+    if nl.body.contains(&exit) {
268
+        return None;
269
+    }
244270
 
245271
     // ---- latch: stride-1 increment, passes only iv back to header ------
246
-    if !check_latch(func, latch, header, iv_param) { return None; }
272
+    if !check_latch(func, latch, header, iv_param) {
273
+        return None;
274
+    }
247275
 
248276
     // ---- compute body_blocks: body − {header, cmp_block, latch} --------
249277
     //
@@ -264,19 +292,22 @@ fn detect_simple_loop(
264292
     // mem2reg may have threaded into OUTER loop latches via dominance-frontier
265293
     // placement. If that param is used outside nl.body, the header's block param
266294
     // becomes undefined after we discard the header block.
267
-    for &bb in body_blocks.iter()
295
+    for &bb in body_blocks
296
+        .iter()
268297
         .chain(std::iter::once(&header))
269298
         .chain(std::iter::once(&cmp_block))
270299
         .chain(std::iter::once(&latch))
271300
     {
272
-        if has_escaping_values(func, bb, &nl.body, preds) { return None; }
301
+        if has_escaping_values(func, bb, &nl.body, preds) {
302
+            return None;
303
+        }
273304
     }
274305
 
275306
     // ---- size check ------------------------------------------------------
276
-    let total_insts: usize = body_blocks.iter()
277
-        .map(|&b| func.block(b).insts.len())
278
-        .sum();
279
-    if total_insts > BODY_SIZE_MAX { return None; }
307
+    let total_insts: usize = body_blocks.iter().map(|&b| func.block(b).insts.len()).sum();
308
+    if total_insts > BODY_SIZE_MAX {
309
+        return None;
310
+    }
280311
 
281312
     let full_unroll_max = if is_do_concurrent {
282313
         DO_CONCURRENT_FULL_UNROLL_MAX
@@ -286,8 +317,12 @@ fn detect_simple_loop(
286317
 
287318
     // ---- trip count ------------------------------------------------------
288319
     let trip_count_i64 = iv_bound - iv_init + 1;
289
-    if trip_count_i64 <= 0 { return None; }
290
-    if trip_count_i64 > full_unroll_max { return None; }
320
+    if trip_count_i64 <= 0 {
321
+        return None;
322
+    }
323
+    if trip_count_i64 > full_unroll_max {
324
+        return None;
325
+    }
291326
 
292327
     Some(LoopShape {
293328
         preheader,
@@ -333,7 +368,9 @@ fn collect_body_chain(
333368
         Some(Terminator::CondBranch { true_dest, .. }) => *true_dest,
334369
         _ => return None,
335370
     };
336
-    if !loop_body.contains(&first) { return None; }
371
+    if !loop_body.contains(&first) {
372
+        return None;
373
+    }
337374
 
338375
     if first == latch {
339376
         // Case (a): the cmp's true-successor is the latch itself.
@@ -347,12 +384,18 @@ fn collect_body_chain(
347384
     let mut chain = Vec::new();
348385
     let mut cur = first;
349386
     loop {
350
-        if !loop_body.contains(&cur) { return None; }
387
+        if !loop_body.contains(&cur) {
388
+            return None;
389
+        }
351390
         chain.push(cur);
352
-        if cur == latch { break; }
391
+        if cur == latch {
392
+            break;
393
+        }
353394
         let blk = func.block(cur);
354395
         // Each block in the chain must have no params (no join point).
355
-        if !blk.params.is_empty() { return None; }
396
+        if !blk.params.is_empty() {
397
+            return None;
398
+        }
356399
         // Its terminator must be an unconditional branch to the next block.
357400
         match &blk.terminator {
358401
             Some(Terminator::Branch(next, args)) if args.is_empty() => {
@@ -360,7 +403,9 @@ fn collect_body_chain(
360403
             }
361404
             _ => return None,
362405
         }
363
-        if chain.len() > 4 { return None; } // safety limit
406
+        if chain.len() > 4 {
407
+            return None;
408
+        } // safety limit
364409
     }
365410
     Some(chain)
366411
 }
@@ -388,8 +433,8 @@ fn detect_bound_and_exit(
388433
 
389434
     // Find the single ICmp that involves the IV.
390435
     let mut cmp_id: Option<ValueId> = None;
391
-    let mut bound: Option<i64>     = None;
392
-    let mut is_lt = false;  // true when we need bound-1
436
+    let mut bound: Option<i64> = None;
437
+    let mut is_lt = false; // true when we need bound-1
393438
 
394439
     for inst in &hdr.insts {
395440
         if let InstKind::ICmp(op, a, b) = &inst.kind {
@@ -402,10 +447,22 @@ fn detect_bound_and_exit(
402447
             };
403448
             let c = resolve_const_int(func, other)?;
404449
             match op {
405
-                CmpOp::Le => { bound = Some(c); is_lt = false; }
406
-                CmpOp::Lt => { bound = Some(c); is_lt = true; }
407
-                CmpOp::Ge => { bound = Some(c); is_lt = false; } // iv >= c means upper = c when commuted
408
-                CmpOp::Gt => { bound = Some(c); is_lt = true; }  // iv > c means upper = c-1 commuted
450
+                CmpOp::Le => {
451
+                    bound = Some(c);
452
+                    is_lt = false;
453
+                }
454
+                CmpOp::Lt => {
455
+                    bound = Some(c);
456
+                    is_lt = true;
457
+                }
458
+                CmpOp::Ge => {
459
+                    bound = Some(c);
460
+                    is_lt = false;
461
+                } // iv >= c means upper = c when commuted
462
+                CmpOp::Gt => {
463
+                    bound = Some(c);
464
+                    is_lt = true;
465
+                } // iv > c means upper = c-1 commuted
409466
                 _ => return None,
410467
             }
411468
             cmp_id = Some(inst.id);
@@ -418,9 +475,13 @@ fn detect_bound_and_exit(
418475
 
419476
     // Terminator must be CondBranch on that cmp.
420477
     match &hdr.terminator {
421
-        Some(Terminator::CondBranch { cond, true_dest, true_args, false_dest, false_args })
422
-            if *cond == cmp_id =>
423
-        {
478
+        Some(Terminator::CondBranch {
479
+            cond,
480
+            true_dest,
481
+            true_args,
482
+            false_dest,
483
+            false_args,
484
+        }) if *cond == cmp_id => {
424485
             // true → body (latch), false → exit.
425486
             // Check which side is the latch. We don't have the latch id here;
426487
             // we'll accept either ordering and return the "false" side as exit.
@@ -445,8 +506,7 @@ fn check_latch(func: &Function, latch: BlockId, header: BlockId, iv: ValueId) ->
445506
 
446507
     // Terminator must be unconditional branch to header with exactly 1 arg.
447508
     let iv_next = match &blk.terminator {
448
-        Some(Terminator::Branch(dest, args)) if *dest == header && args.len() == 1 =>
449
-            args[0],
509
+        Some(Terminator::Branch(dest, args)) if *dest == header && args.len() == 1 => args[0],
450510
         _ => return false,
451511
     };
452512
 
@@ -455,8 +515,16 @@ fn check_latch(func: &Function, latch: BlockId, header: BlockId, iv: ValueId) ->
455515
         if inst.id == iv_next {
456516
             match &inst.kind {
457517
                 InstKind::IAdd(a, b) => {
458
-                    let (is_iv, other) = if *a == iv { (true, *b) } else if *b == iv { (true, *a) } else { (false, *a) };
459
-                    if !is_iv { return false; }
518
+                    let (is_iv, other) = if *a == iv {
519
+                        (true, *b)
520
+                    } else if *b == iv {
521
+                        (true, *a)
522
+                    } else {
523
+                        (false, *a)
524
+                    };
525
+                    if !is_iv {
526
+                        return false;
527
+                    }
460528
                     return resolve_const_int(func, other) == Some(1);
461529
                 }
462530
                 _ => return false,
@@ -484,24 +552,36 @@ fn has_escaping_values(
484552
     // latch it becomes undefined after unrolling removes the block.
485553
     let latch_blk = func.block(latch);
486554
     let mut latch_defs: HashSet<ValueId> = HashSet::new();
487
-    for bp   in &latch_blk.params { latch_defs.insert(bp.id); }
488
-    for inst in &latch_blk.insts  { latch_defs.insert(inst.id); }
555
+    for bp in &latch_blk.params {
556
+        latch_defs.insert(bp.id);
557
+    }
558
+    for inst in &latch_blk.insts {
559
+        latch_defs.insert(inst.id);
560
+    }
489561
 
490
-    if latch_defs.is_empty() { return false; }
562
+    if latch_defs.is_empty() {
563
+        return false;
564
+    }
491565
 
492566
     // Check every block outside the loop body for uses of those values.
493567
     for block in &func.blocks {
494
-        if body.contains(&block.id) { continue; }
568
+        if body.contains(&block.id) {
569
+            continue;
570
+        }
495571
         // Check instruction operands.
496572
         for inst in &block.insts {
497573
             for use_id in inst_uses(&inst.kind) {
498
-                if latch_defs.contains(&use_id) { return true; }
574
+                if latch_defs.contains(&use_id) {
575
+                    return true;
576
+                }
499577
             }
500578
         }
501579
         // Check terminator operands.
502580
         if let Some(term) = &block.terminator {
503581
             for &use_id in terminator_uses_vec(term).iter() {
504
-                if latch_defs.contains(&use_id) { return true; }
582
+                if latch_defs.contains(&use_id) {
583
+                    return true;
584
+                }
505585
             }
506586
         }
507587
         // Also check block params of outside blocks that receive args from latch.
@@ -526,15 +606,20 @@ fn block_contains_load(func: &Function, block: BlockId) -> bool {
526606
 fn terminator_uses_vec(term: &Terminator) -> Vec<ValueId> {
527607
     let mut out = Vec::new();
528608
     match term {
529
-        Terminator::Return(Some(v))          => out.push(*v),
530
-        Terminator::Branch(_, args)           => out.extend(args),
531
-        Terminator::CondBranch { cond, true_args, false_args, .. } => {
609
+        Terminator::Return(Some(v)) => out.push(*v),
610
+        Terminator::Branch(_, args) => out.extend(args),
611
+        Terminator::CondBranch {
612
+            cond,
613
+            true_args,
614
+            false_args,
615
+            ..
616
+        } => {
532617
             out.push(*cond);
533618
             out.extend(true_args);
534619
             out.extend(false_args);
535620
         }
536
-        Terminator::Switch { selector, .. }  => out.push(*selector),
537
-        _                                    => {}
621
+        Terminator::Switch { selector, .. } => out.push(*selector),
622
+        _ => {}
538623
     }
539624
     out
540625
 }
@@ -550,12 +635,17 @@ fn inst_uses(kind: &InstKind) -> Vec<ValueId> {
550635
 
551636
 fn do_unroll(func: &mut Function, shape: LoopShape) {
552637
     // Collect per-body-block instructions once (before we mutate func).
553
-    let body_snapshots: Vec<Vec<Inst>> = shape.body_blocks.iter()
638
+    let body_snapshots: Vec<Vec<Inst>> = shape
639
+        .body_blocks
640
+        .iter()
554641
         .map(|&b| func.block(b).insts.clone())
555642
         .collect();
556643
 
557644
     // Determine the IV width.
558
-    let iv_width = match &shape.iv_ty { IrType::Int(w) => *w, _ => IntWidth::I32 };
645
+    let iv_width = match &shape.iv_ty {
646
+        IrType::Int(w) => *w,
647
+        _ => IntWidth::I32,
648
+    };
559649
 
560650
     // For each iteration, we create one new block per body block, cloned
561651
     // with the IV substituted by a constant. The chain is:
@@ -673,8 +763,7 @@ fn do_unroll(func: &mut Function, shape: LoopShape) {
673763
                     (after_iter, exit_args.clone())
674764
                 };
675765
                 let _ = original_body_next[bi]; // consumed above
676
-                func.block_mut(cur_blk).terminator =
677
-                    Some(Terminator::Branch(next_blk, args));
766
+                func.block_mut(cur_blk).terminator = Some(Terminator::Branch(next_blk, args));
678767
             }
679768
         }
680769
     }
@@ -690,9 +779,9 @@ fn do_unroll(func: &mut Function, shape: LoopShape) {
690779
         Some(Terminator::Branch(first_block, preheader_args));
691780
 
692781
     // Mark loop control blocks as Unreachable → prune_unreachable removes them.
693
-    func.block_mut(shape.header).terminator   = Some(Terminator::Unreachable);
782
+    func.block_mut(shape.header).terminator = Some(Terminator::Unreachable);
694783
     func.block_mut(shape.cmp_block).terminator = Some(Terminator::Unreachable);
695
-    func.block_mut(shape.latch).terminator     = Some(Terminator::Unreachable);
784
+    func.block_mut(shape.latch).terminator = Some(Terminator::Unreachable);
696785
     for &b in &shape.body_blocks {
697786
         func.block_mut(b).terminator = Some(Terminator::Unreachable);
698787
     }
@@ -703,30 +792,30 @@ fn remap_kind(kind: &InstKind, subst: &HashMap<ValueId, ValueId>) -> InstKind {
703792
     let r = |v: &ValueId| *subst.get(v).unwrap_or(v);
704793
     match kind {
705794
         // Constants — no operands.
706
-        InstKind::ConstInt(v, w)     => InstKind::ConstInt(*v, *w),
707
-        InstKind::ConstFloat(v, w)   => InstKind::ConstFloat(*v, *w),
708
-        InstKind::ConstBool(v)       => InstKind::ConstBool(*v),
709
-        InstKind::ConstString(v)     => InstKind::ConstString(v.clone()),
710
-        InstKind::Undef(t)           => InstKind::Undef(t.clone()),
711
-        InstKind::GlobalAddr(s)      => InstKind::GlobalAddr(s.clone()),
795
+        InstKind::ConstInt(v, w) => InstKind::ConstInt(*v, *w),
796
+        InstKind::ConstFloat(v, w) => InstKind::ConstFloat(*v, *w),
797
+        InstKind::ConstBool(v) => InstKind::ConstBool(*v),
798
+        InstKind::ConstString(v) => InstKind::ConstString(v.clone()),
799
+        InstKind::Undef(t) => InstKind::Undef(t.clone()),
800
+        InstKind::GlobalAddr(s) => InstKind::GlobalAddr(s.clone()),
712801
 
713802
         // Integer arithmetic.
714
-        InstKind::IAdd(a, b)  => InstKind::IAdd(r(a), r(b)),
715
-        InstKind::ISub(a, b)  => InstKind::ISub(r(a), r(b)),
716
-        InstKind::IMul(a, b)  => InstKind::IMul(r(a), r(b)),
717
-        InstKind::IDiv(a, b)  => InstKind::IDiv(r(a), r(b)),
718
-        InstKind::IMod(a, b)  => InstKind::IMod(r(a), r(b)),
719
-        InstKind::INeg(a)     => InstKind::INeg(r(a)),
803
+        InstKind::IAdd(a, b) => InstKind::IAdd(r(a), r(b)),
804
+        InstKind::ISub(a, b) => InstKind::ISub(r(a), r(b)),
805
+        InstKind::IMul(a, b) => InstKind::IMul(r(a), r(b)),
806
+        InstKind::IDiv(a, b) => InstKind::IDiv(r(a), r(b)),
807
+        InstKind::IMod(a, b) => InstKind::IMod(r(a), r(b)),
808
+        InstKind::INeg(a) => InstKind::INeg(r(a)),
720809
 
721810
         // Float arithmetic.
722
-        InstKind::FAdd(a, b)  => InstKind::FAdd(r(a), r(b)),
723
-        InstKind::FSub(a, b)  => InstKind::FSub(r(a), r(b)),
724
-        InstKind::FMul(a, b)  => InstKind::FMul(r(a), r(b)),
725
-        InstKind::FDiv(a, b)  => InstKind::FDiv(r(a), r(b)),
726
-        InstKind::FNeg(a)     => InstKind::FNeg(r(a)),
727
-        InstKind::FAbs(a)     => InstKind::FAbs(r(a)),
728
-        InstKind::FSqrt(a)    => InstKind::FSqrt(r(a)),
729
-        InstKind::FPow(a, b)  => InstKind::FPow(r(a), r(b)),
811
+        InstKind::FAdd(a, b) => InstKind::FAdd(r(a), r(b)),
812
+        InstKind::FSub(a, b) => InstKind::FSub(r(a), r(b)),
813
+        InstKind::FMul(a, b) => InstKind::FMul(r(a), r(b)),
814
+        InstKind::FDiv(a, b) => InstKind::FDiv(r(a), r(b)),
815
+        InstKind::FNeg(a) => InstKind::FNeg(r(a)),
816
+        InstKind::FAbs(a) => InstKind::FAbs(r(a)),
817
+        InstKind::FSqrt(a) => InstKind::FSqrt(r(a)),
818
+        InstKind::FPow(a, b) => InstKind::FPow(r(a), r(b)),
730819
 
731820
         // Comparison.
732821
         InstKind::ICmp(op, a, b) => InstKind::ICmp(*op, r(a), r(b)),
@@ -734,49 +823,50 @@ fn remap_kind(kind: &InstKind, subst: &HashMap<ValueId, ValueId>) -> InstKind {
734823
 
735824
         // Logic.
736825
         InstKind::And(a, b) => InstKind::And(r(a), r(b)),
737
-        InstKind::Or(a, b)  => InstKind::Or(r(a), r(b)),
738
-        InstKind::Not(a)    => InstKind::Not(r(a)),
826
+        InstKind::Or(a, b) => InstKind::Or(r(a), r(b)),
827
+        InstKind::Not(a) => InstKind::Not(r(a)),
739828
 
740829
         // Select.
741830
         InstKind::Select(c, t, f) => InstKind::Select(r(c), r(t), r(f)),
742831
 
743832
         // Bitwise.
744
-        InstKind::BitAnd(a, b)           => InstKind::BitAnd(r(a), r(b)),
745
-        InstKind::BitOr(a, b)            => InstKind::BitOr(r(a), r(b)),
746
-        InstKind::BitXor(a, b)           => InstKind::BitXor(r(a), r(b)),
747
-        InstKind::BitNot(a)              => InstKind::BitNot(r(a)),
748
-        InstKind::Shl(a, b)              => InstKind::Shl(r(a), r(b)),
749
-        InstKind::LShr(a, b)             => InstKind::LShr(r(a), r(b)),
750
-        InstKind::AShr(a, b)             => InstKind::AShr(r(a), r(b)),
751
-        InstKind::CountLeadingZeros(a)   => InstKind::CountLeadingZeros(r(a)),
752
-        InstKind::CountTrailingZeros(a)  => InstKind::CountTrailingZeros(r(a)),
753
-        InstKind::PopCount(a)            => InstKind::PopCount(r(a)),
833
+        InstKind::BitAnd(a, b) => InstKind::BitAnd(r(a), r(b)),
834
+        InstKind::BitOr(a, b) => InstKind::BitOr(r(a), r(b)),
835
+        InstKind::BitXor(a, b) => InstKind::BitXor(r(a), r(b)),
836
+        InstKind::BitNot(a) => InstKind::BitNot(r(a)),
837
+        InstKind::Shl(a, b) => InstKind::Shl(r(a), r(b)),
838
+        InstKind::LShr(a, b) => InstKind::LShr(r(a), r(b)),
839
+        InstKind::AShr(a, b) => InstKind::AShr(r(a), r(b)),
840
+        InstKind::CountLeadingZeros(a) => InstKind::CountLeadingZeros(r(a)),
841
+        InstKind::CountTrailingZeros(a) => InstKind::CountTrailingZeros(r(a)),
842
+        InstKind::PopCount(a) => InstKind::PopCount(r(a)),
754843
 
755844
         // Conversions.
756
-        InstKind::IntToFloat(a, w)    => InstKind::IntToFloat(r(a), *w),
757
-        InstKind::FloatToInt(a, w)    => InstKind::FloatToInt(r(a), *w),
758
-        InstKind::FloatExtend(a, w)   => InstKind::FloatExtend(r(a), *w),
759
-        InstKind::FloatTrunc(a, w)    => InstKind::FloatTrunc(r(a), *w),
760
-        InstKind::IntExtend(a, w, s)  => InstKind::IntExtend(r(a), *w, *s),
761
-        InstKind::IntTrunc(a, w)      => InstKind::IntTrunc(r(a), *w),
762
-        InstKind::PtrToInt(a)         => InstKind::PtrToInt(r(a)),
763
-        InstKind::IntToPtr(a, ty)     => InstKind::IntToPtr(r(a), ty.clone()),
845
+        InstKind::IntToFloat(a, w) => InstKind::IntToFloat(r(a), *w),
846
+        InstKind::FloatToInt(a, w) => InstKind::FloatToInt(r(a), *w),
847
+        InstKind::FloatExtend(a, w) => InstKind::FloatExtend(r(a), *w),
848
+        InstKind::FloatTrunc(a, w) => InstKind::FloatTrunc(r(a), *w),
849
+        InstKind::IntExtend(a, w, s) => InstKind::IntExtend(r(a), *w, *s),
850
+        InstKind::IntTrunc(a, w) => InstKind::IntTrunc(r(a), *w),
851
+        InstKind::PtrToInt(a) => InstKind::PtrToInt(r(a)),
852
+        InstKind::IntToPtr(a, ty) => InstKind::IntToPtr(r(a), ty.clone()),
764853
 
765854
         // Memory.
766
-        InstKind::Alloca(t)  => InstKind::Alloca(t.clone()),
767
-        InstKind::Load(a)    => InstKind::Load(r(a)),
855
+        InstKind::Alloca(t) => InstKind::Alloca(t.clone()),
856
+        InstKind::Load(a) => InstKind::Load(r(a)),
768857
         InstKind::Store(v, p) => InstKind::Store(r(v), r(p)),
769
-        InstKind::GetElementPtr(base, idxs) =>
770
-            InstKind::GetElementPtr(r(base), idxs.iter().map(&r).collect()),
858
+        InstKind::GetElementPtr(base, idxs) => {
859
+            InstKind::GetElementPtr(r(base), idxs.iter().map(&r).collect())
860
+        }
771861
 
772862
         // Calls.
773
-        InstKind::Call(f, args) =>
774
-            InstKind::Call(f.clone(), args.iter().map(&r).collect()),
775
-        InstKind::RuntimeCall(f, args) =>
776
-            InstKind::RuntimeCall(f.clone(), args.iter().map(&r).collect()),
863
+        InstKind::Call(f, args) => InstKind::Call(f.clone(), args.iter().map(&r).collect()),
864
+        InstKind::RuntimeCall(f, args) => {
865
+            InstKind::RuntimeCall(f.clone(), args.iter().map(&r).collect())
866
+        }
777867
 
778868
         // Aggregates.
779
-        InstKind::ExtractField(v, idx)     => InstKind::ExtractField(r(v), *idx),
869
+        InstKind::ExtractField(v, idx) => InstKind::ExtractField(r(v), *idx),
780870
         InstKind::InsertField(v, idx, fld) => InstKind::InsertField(r(v), *idx, r(fld)),
781871
     }
782872
 }
@@ -788,11 +878,13 @@ fn remap_kind(kind: &InstKind, subst: &HashMap<ValueId, ValueId>) -> InstKind {
788878
 #[cfg(test)]
789879
 mod tests {
790880
     use super::*;
791
-    use crate::ir::types::{IrType, IntWidth};
792
-    use crate::opt::pass::Pass;
881
+    use crate::ir::types::{IntWidth, IrType};
793882
     use crate::lexer::Span;
883
+    use crate::opt::pass::Pass;
794884
 
795
-    fn span() -> Span { super::dummy_span() }
885
+    fn span() -> Span {
886
+        super::dummy_span()
887
+    }
796888
 
797889
     /// Build a minimal Module with one function containing a simple
798890
     /// counted loop: do i = 1, N; a(i_offset) = const(42); end do
@@ -806,77 +898,94 @@ mod tests {
806898
 
807899
         // Allocate block IDs.
808900
         let header_id = f.create_block(&format!("{}_check", prefix));
809
-        let latch_id  = f.create_block(&format!("{}_body", prefix));
810
-        let exit_id   = f.create_block("exit");
811
-        let entry_id  = f.entry; // preheader
901
+        let latch_id = f.create_block(&format!("{}_body", prefix));
902
+        let exit_id = f.create_block("exit");
903
+        let entry_id = f.entry; // preheader
812904
 
813905
         // ---- entry (preheader) -------------------------------------------
814906
         // const lo
815907
         let lo_val = f.next_value_id();
816908
         f.block_mut(entry_id).insts.push(Inst {
817
-            id: lo_val, ty: IrType::Int(IntWidth::I64), span: span(),
909
+            id: lo_val,
910
+            ty: IrType::Int(IntWidth::I64),
911
+            span: span(),
818912
             kind: InstKind::ConstInt(lo as i128, IntWidth::I64),
819913
         });
820914
         // alloca for the "array" (just a slot we store into)
821915
         let alloca_val = f.next_value_id();
822916
         f.block_mut(entry_id).insts.push(Inst {
823
-            id: alloca_val, ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I64))), span: span(),
917
+            id: alloca_val,
918
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I64))),
919
+            span: span(),
824920
             kind: InstKind::Alloca(IrType::Int(IntWidth::I64)),
825921
         });
826922
         // br header(lo)
827
-        f.block_mut(entry_id).terminator =
828
-            Some(Terminator::Branch(header_id, vec![lo_val]));
923
+        f.block_mut(entry_id).terminator = Some(Terminator::Branch(header_id, vec![lo_val]));
829924
 
830925
         // ---- header (%i) -------------------------------------------------
831926
         let iv_param = f.next_value_id();
832927
         f.block_mut(header_id).params.push(BlockParam {
833
-            id: iv_param, ty: IrType::Int(IntWidth::I64),
928
+            id: iv_param,
929
+            ty: IrType::Int(IntWidth::I64),
834930
         });
835931
         // const hi
836932
         let hi_val = f.next_value_id();
837933
         f.block_mut(header_id).insts.push(Inst {
838
-            id: hi_val, ty: IrType::Int(IntWidth::I64), span: span(),
934
+            id: hi_val,
935
+            ty: IrType::Int(IntWidth::I64),
936
+            span: span(),
839937
             kind: InstKind::ConstInt(hi as i128, IntWidth::I64),
840938
         });
841939
         // %cmp = icmp.sle %i, hi
842940
         let cmp_val = f.next_value_id();
843941
         f.block_mut(header_id).insts.push(Inst {
844
-            id: cmp_val, ty: IrType::Bool, span: span(),
942
+            id: cmp_val,
943
+            ty: IrType::Bool,
944
+            span: span(),
845945
             kind: InstKind::ICmp(CmpOp::Le, iv_param, hi_val),
846946
         });
847947
         // condBr %cmp, latch, exit
848948
         f.block_mut(header_id).terminator = Some(Terminator::CondBranch {
849949
             cond: cmp_val,
850
-            true_dest: latch_id, true_args: vec![],
851
-            false_dest: exit_id, false_args: vec![],
950
+            true_dest: latch_id,
951
+            true_args: vec![],
952
+            false_dest: exit_id,
953
+            false_args: vec![],
852954
         });
853955
 
854956
         // ---- latch -------------------------------------------------------
855957
         // Store 42 to the alloca (simulates a(i) = 42).
856958
         let const42 = f.next_value_id();
857959
         f.block_mut(latch_id).insts.push(Inst {
858
-            id: const42, ty: IrType::Int(IntWidth::I64), span: span(),
960
+            id: const42,
961
+            ty: IrType::Int(IntWidth::I64),
962
+            span: span(),
859963
             kind: InstKind::ConstInt(42, IntWidth::I64),
860964
         });
861965
         let store_id = f.next_value_id();
862966
         f.block_mut(latch_id).insts.push(Inst {
863
-            id: store_id, ty: IrType::Void, span: span(),
967
+            id: store_id,
968
+            ty: IrType::Void,
969
+            span: span(),
864970
             kind: InstKind::Store(const42, alloca_val),
865971
         });
866972
         // %i_next = iadd %i, 1
867973
         let one = f.next_value_id();
868974
         f.block_mut(latch_id).insts.push(Inst {
869
-            id: one, ty: IrType::Int(IntWidth::I64), span: span(),
975
+            id: one,
976
+            ty: IrType::Int(IntWidth::I64),
977
+            span: span(),
870978
             kind: InstKind::ConstInt(1, IntWidth::I64),
871979
         });
872980
         let i_next = f.next_value_id();
873981
         f.block_mut(latch_id).insts.push(Inst {
874
-            id: i_next, ty: IrType::Int(IntWidth::I64), span: span(),
982
+            id: i_next,
983
+            ty: IrType::Int(IntWidth::I64),
984
+            span: span(),
875985
             kind: InstKind::IAdd(iv_param, one),
876986
         });
877987
         // br header(%i_next)
878
-        f.block_mut(latch_id).terminator =
879
-            Some(Terminator::Branch(header_id, vec![i_next]));
988
+        f.block_mut(latch_id).terminator = Some(Terminator::Branch(header_id, vec![i_next]));
880989
 
881990
         // ---- exit --------------------------------------------------------
882991
         f.block_mut(exit_id).terminator = Some(Terminator::Return(None));
@@ -902,9 +1011,17 @@ mod tests {
9021011
         assert_eq!(f.blocks.len(), 6, "expected entry + 4 iter blocks + exit");
9031012
 
9041013
         // Each iteration block has a ConstInt for that iteration's IV value.
905
-        let all_iv_consts: Vec<i128> = f.blocks.iter()
1014
+        let all_iv_consts: Vec<i128> = f
1015
+            .blocks
1016
+            .iter()
9061017
             .flat_map(|b| b.insts.iter())
907
-            .filter_map(|i| if let InstKind::ConstInt(v, _) = i.kind { Some(v) } else { None })
1018
+            .filter_map(|i| {
1019
+                if let InstKind::ConstInt(v, _) = i.kind {
1020
+                    Some(v)
1021
+                } else {
1022
+                    None
1023
+                }
1024
+            })
9081025
             .collect();
9091026
         assert!(all_iv_consts.contains(&1), "IV=1 should appear");
9101027
         assert!(all_iv_consts.contains(&2), "IV=2 should appear");
@@ -925,7 +1042,10 @@ mod tests {
9251042
         let mut m = build_counted_loop_with_prefix(1, 10, "doconc");
9261043
         let pass = LoopUnroll;
9271044
         let changed = pass.run(&mut m);
928
-        assert!(changed, "DO CONCURRENT trip-count-10 loop should fully unroll");
1045
+        assert!(
1046
+            changed,
1047
+            "DO CONCURRENT trip-count-10 loop should fully unroll"
1048
+        );
9291049
 
9301050
         let f = &m.functions[0];
9311051
         assert_eq!(f.blocks.len(), 12, "expected entry + 10 iter blocks + exit");
@@ -946,59 +1066,80 @@ mod tests {
9461066
         let mut m = Module::new("test".into());
9471067
         let mut f = Function::new("reduce".into(), vec![], IrType::Void);
9481068
         let header_id = f.create_block("header");
949
-        let latch_id  = f.create_block("latch");
950
-        let exit_id   = f.create_block("exit");
951
-        let entry_id  = f.entry;
1069
+        let latch_id = f.create_block("latch");
1070
+        let exit_id = f.create_block("exit");
1071
+        let entry_id = f.entry;
9521072
 
9531073
         // Entry: br header(1, 0)
9541074
         let lo = f.next_value_id();
9551075
         f.block_mut(entry_id).insts.push(Inst {
956
-            id: lo, ty: IrType::Int(IntWidth::I64), span: span(),
1076
+            id: lo,
1077
+            ty: IrType::Int(IntWidth::I64),
1078
+            span: span(),
9571079
             kind: InstKind::ConstInt(1, IntWidth::I64),
9581080
         });
9591081
         let z = f.next_value_id();
9601082
         f.block_mut(entry_id).insts.push(Inst {
961
-            id: z, ty: IrType::Int(IntWidth::I64), span: span(),
1083
+            id: z,
1084
+            ty: IrType::Int(IntWidth::I64),
1085
+            span: span(),
9621086
             kind: InstKind::ConstInt(0, IntWidth::I64),
9631087
         });
964
-        f.block_mut(entry_id).terminator =
965
-            Some(Terminator::Branch(header_id, vec![lo, z]));
1088
+        f.block_mut(entry_id).terminator = Some(Terminator::Branch(header_id, vec![lo, z]));
9661089
 
9671090
         // Header: 2 params (iv, acc)
968
-        let iv  = f.next_value_id();
1091
+        let iv = f.next_value_id();
9691092
         let acc = f.next_value_id();
970
-        f.block_mut(header_id).params.push(BlockParam { id: iv,  ty: IrType::Int(IntWidth::I64) });
971
-        f.block_mut(header_id).params.push(BlockParam { id: acc, ty: IrType::Int(IntWidth::I64) });
1093
+        f.block_mut(header_id).params.push(BlockParam {
1094
+            id: iv,
1095
+            ty: IrType::Int(IntWidth::I64),
1096
+        });
1097
+        f.block_mut(header_id).params.push(BlockParam {
1098
+            id: acc,
1099
+            ty: IrType::Int(IntWidth::I64),
1100
+        });
9721101
         let hi = f.next_value_id();
9731102
         f.block_mut(header_id).insts.push(Inst {
974
-            id: hi, ty: IrType::Int(IntWidth::I64), span: span(),
1103
+            id: hi,
1104
+            ty: IrType::Int(IntWidth::I64),
1105
+            span: span(),
9751106
             kind: InstKind::ConstInt(4, IntWidth::I64),
9761107
         });
9771108
         let cmp = f.next_value_id();
9781109
         f.block_mut(header_id).insts.push(Inst {
979
-            id: cmp, ty: IrType::Bool, span: span(),
1110
+            id: cmp,
1111
+            ty: IrType::Bool,
1112
+            span: span(),
9801113
             kind: InstKind::ICmp(CmpOp::Le, iv, hi),
9811114
         });
9821115
         f.block_mut(header_id).terminator = Some(Terminator::CondBranch {
9831116
             cond: cmp,
984
-            true_dest: latch_id, true_args: vec![],
985
-            false_dest: exit_id, false_args: vec![acc],
1117
+            true_dest: latch_id,
1118
+            true_args: vec![],
1119
+            false_dest: exit_id,
1120
+            false_args: vec![acc],
9861121
         });
9871122
 
9881123
         // Latch: acc_next = acc + iv; i_next = iv + 1; br header(i_next, acc_next)
9891124
         let one = f.next_value_id();
9901125
         f.block_mut(latch_id).insts.push(Inst {
991
-            id: one, ty: IrType::Int(IntWidth::I64), span: span(),
1126
+            id: one,
1127
+            ty: IrType::Int(IntWidth::I64),
1128
+            span: span(),
9921129
             kind: InstKind::ConstInt(1, IntWidth::I64),
9931130
         });
9941131
         let acc_next = f.next_value_id();
9951132
         f.block_mut(latch_id).insts.push(Inst {
996
-            id: acc_next, ty: IrType::Int(IntWidth::I64), span: span(),
1133
+            id: acc_next,
1134
+            ty: IrType::Int(IntWidth::I64),
1135
+            span: span(),
9971136
             kind: InstKind::IAdd(acc, iv),
9981137
         });
9991138
         let i_next = f.next_value_id();
10001139
         f.block_mut(latch_id).insts.push(Inst {
1001
-            id: i_next, ty: IrType::Int(IntWidth::I64), span: span(),
1140
+            id: i_next,
1141
+            ty: IrType::Int(IntWidth::I64),
1142
+            span: span(),
10021143
             kind: InstKind::IAdd(iv, one),
10031144
         });
10041145
         f.block_mut(latch_id).terminator =
@@ -1006,14 +1147,20 @@ mod tests {
10061147
 
10071148
         // Exit: acc param, return
10081149
         let acc_out = f.next_value_id();
1009
-        f.block_mut(exit_id).params.push(BlockParam { id: acc_out, ty: IrType::Int(IntWidth::I64) });
1150
+        f.block_mut(exit_id).params.push(BlockParam {
1151
+            id: acc_out,
1152
+            ty: IrType::Int(IntWidth::I64),
1153
+        });
10101154
         f.block_mut(exit_id).terminator = Some(Terminator::Return(None));
10111155
 
10121156
         m.add_function(f);
10131157
 
10141158
         let pass = LoopUnroll;
10151159
         let changed = pass.run(&mut m);
1016
-        assert!(!changed, "reduction loop with 2 header params should not be unrolled");
1160
+        assert!(
1161
+            !changed,
1162
+            "reduction loop with 2 header params should not be unrolled"
1163
+        );
10171164
     }
10181165
 
10191166
     #[test]
@@ -1185,56 +1332,67 @@ mod tests {
11851332
         let mut m = Module::new("test".into());
11861333
         let mut f = Function::new("escape_test".into(), vec![], IrType::Void);
11871334
 
1188
-        let header_id   = f.create_block("header");
1189
-        let latch_id    = f.create_block("latch");
1190
-        let exit_id     = f.create_block("exit");
1335
+        let header_id = f.create_block("header");
1336
+        let latch_id = f.create_block("latch");
1337
+        let exit_id = f.create_block("exit");
11911338
         let outer_latch = f.create_block("outer_latch");
1192
-        let outer_dest  = f.create_block("outer_dest");
1193
-        let entry_id    = f.entry;
1339
+        let outer_dest = f.create_block("outer_dest");
1340
+        let entry_id = f.entry;
11941341
 
11951342
         // Entry: const 1; br header(1)
11961343
         let lo = f.next_value_id();
11971344
         f.block_mut(entry_id).insts.push(Inst {
1198
-            id: lo, ty: IrType::Int(IntWidth::I64), span: span(),
1345
+            id: lo,
1346
+            ty: IrType::Int(IntWidth::I64),
1347
+            span: span(),
11991348
             kind: InstKind::ConstInt(1, IntWidth::I64),
12001349
         });
1201
-        f.block_mut(entry_id).terminator =
1202
-            Some(Terminator::Branch(header_id, vec![lo]));
1350
+        f.block_mut(entry_id).terminator = Some(Terminator::Branch(header_id, vec![lo]));
12031351
 
12041352
         // Header: block param %iv; icmp %iv ≤ 3; condBr latch, exit
12051353
         let iv = f.next_value_id();
12061354
         f.block_mut(header_id).params.push(BlockParam {
1207
-            id: iv, ty: IrType::Int(IntWidth::I64),
1355
+            id: iv,
1356
+            ty: IrType::Int(IntWidth::I64),
12081357
         });
12091358
         let hi_c = f.next_value_id();
12101359
         f.block_mut(header_id).insts.push(Inst {
1211
-            id: hi_c, ty: IrType::Int(IntWidth::I64), span: span(),
1360
+            id: hi_c,
1361
+            ty: IrType::Int(IntWidth::I64),
1362
+            span: span(),
12121363
             kind: InstKind::ConstInt(3, IntWidth::I64),
12131364
         });
12141365
         let cmp = f.next_value_id();
12151366
         f.block_mut(header_id).insts.push(Inst {
1216
-            id: cmp, ty: IrType::Bool, span: span(),
1367
+            id: cmp,
1368
+            ty: IrType::Bool,
1369
+            span: span(),
12171370
             kind: InstKind::ICmp(CmpOp::Le, iv, hi_c),
12181371
         });
12191372
         f.block_mut(header_id).terminator = Some(Terminator::CondBranch {
12201373
             cond: cmp,
1221
-            true_dest: latch_id, true_args: vec![],
1222
-            false_dest: exit_id, false_args: vec![],
1374
+            true_dest: latch_id,
1375
+            true_args: vec![],
1376
+            false_dest: exit_id,
1377
+            false_args: vec![],
12231378
         });
12241379
 
12251380
         // Latch: %next = iadd %iv, 1; br header(%next)
12261381
         let one = f.next_value_id();
12271382
         f.block_mut(latch_id).insts.push(Inst {
1228
-            id: one, ty: IrType::Int(IntWidth::I64), span: span(),
1383
+            id: one,
1384
+            ty: IrType::Int(IntWidth::I64),
1385
+            span: span(),
12291386
             kind: InstKind::ConstInt(1, IntWidth::I64),
12301387
         });
12311388
         let nxt = f.next_value_id();
12321389
         f.block_mut(latch_id).insts.push(Inst {
1233
-            id: nxt, ty: IrType::Int(IntWidth::I64), span: span(),
1390
+            id: nxt,
1391
+            ty: IrType::Int(IntWidth::I64),
1392
+            span: span(),
12341393
             kind: InstKind::IAdd(iv, one),
12351394
         });
1236
-        f.block_mut(latch_id).terminator =
1237
-            Some(Terminator::Branch(header_id, vec![nxt]));
1395
+        f.block_mut(latch_id).terminator = Some(Terminator::Branch(header_id, vec![nxt]));
12381396
 
12391397
         // Exit: ret void
12401398
         f.block_mut(exit_id).terminator = Some(Terminator::Return(None));
@@ -1242,13 +1400,13 @@ mod tests {
12421400
         // outer_latch: br outer_dest(%iv)
12431401
         // Simulates an outer-loop latch that mem2reg threaded %iv through.
12441402
         // %iv is the header's block param — it escapes into this external block.
1245
-        f.block_mut(outer_latch).terminator =
1246
-            Some(Terminator::Branch(outer_dest, vec![iv]));
1403
+        f.block_mut(outer_latch).terminator = Some(Terminator::Branch(outer_dest, vec![iv]));
12471404
 
12481405
         // outer_dest(%x): ret void
12491406
         let x = f.next_value_id();
12501407
         f.block_mut(outer_dest).params.push(BlockParam {
1251
-            id: x, ty: IrType::Int(IntWidth::I64),
1408
+            id: x,
1409
+            ty: IrType::Int(IntWidth::I64),
12521410
         });
12531411
         f.block_mut(outer_dest).terminator = Some(Terminator::Return(None));
12541412
 
src/opt/unswitch.rsmodified
332 lines changed — click to load
@@ -26,11 +26,11 @@
2626
 //! Gated on body size (≤ UNSWITCH_MAX_BODY instructions) to prevent
2727
 //! code bloat. Fires at O2+.
2828
 
29
-use std::collections::{HashMap, HashSet};
30
-use crate::ir::inst::*;
31
-use crate::ir::walk::{find_natural_loops, predecessors, prune_unreachable};
3229
 use super::loop_utils::{find_preheader, loop_defined_values};
3330
 use super::pass::Pass;
31
+use crate::ir::inst::*;
32
+use crate::ir::walk::{find_natural_loops, predecessors, prune_unreachable};
33
+use std::collections::{HashMap, HashSet};
3434
 
3535
 /// Maximum number of instructions in the loop body to consider for
3636
 /// unswitching. Unswitching doubles the code, so keep this tight.
@@ -38,15 +38,26 @@ const UNSWITCH_MAX_BODY: usize = 50;
3838
 
3939
 pub struct LoopUnswitch;
4040
 
41
-type UnswitchCandidate = (BlockId, ValueId, BlockId, Vec<ValueId>, BlockId, Vec<ValueId>);
41
+type UnswitchCandidate = (
42
+    BlockId,
43
+    ValueId,
44
+    BlockId,
45
+    Vec<ValueId>,
46
+    BlockId,
47
+    Vec<ValueId>,
48
+);
4249
 
4350
 impl Pass for LoopUnswitch {
44
-    fn name(&self) -> &'static str { "loop-unswitch" }
51
+    fn name(&self) -> &'static str {
52
+        "loop-unswitch"
53
+    }
4554
 
4655
     fn run(&self, module: &mut Module) -> bool {
4756
         let mut changed = false;
4857
         for func in &mut module.functions {
49
-            if unswitch_in_function(func) { changed = true; }
58
+            if unswitch_in_function(func) {
59
+                changed = true;
60
+            }
5061
         }
5162
         changed
5263
     }
@@ -60,19 +71,22 @@ fn unswitch_in_function(func: &mut Function) -> bool {
6071
     let preds = predecessors(func);
6172
 
6273
     for lp in &loops {
63
-        let Some(ph_id) = find_preheader(func, lp, &preds) else { continue };
74
+        let Some(ph_id) = find_preheader(func, lp, &preds) else {
75
+            continue;
76
+        };
6477
 
6578
         // Size guard.
66
-        let total_insts: usize = lp.body.iter()
67
-            .map(|&b| func.block(b).insts.len())
68
-            .sum();
69
-        if total_insts > UNSWITCH_MAX_BODY { continue; }
79
+        let total_insts: usize = lp.body.iter().map(|&b| func.block(b).insts.len()).sum();
80
+        if total_insts > UNSWITCH_MAX_BODY {
81
+            continue;
82
+        }
7083
 
7184
         // Find a CondBranch inside the loop whose condition is invariant.
7285
         let loop_defs = loop_defined_values(func, lp);
7386
 
7487
         let candidate = find_unswitch_candidate(func, lp, &loop_defs);
75
-        let Some((cond_block, cond_val, true_dest, true_args, false_dest, false_args)) = candidate else {
88
+        let Some((cond_block, cond_val, true_dest, true_args, false_dest, false_args)) = candidate
89
+        else {
7690
             continue;
7791
         };
7892
 
@@ -91,7 +105,8 @@ fn unswitch_in_function(func: &mut Function) -> bool {
91105
         let true_cond_block = true_map[&cond_block];
92106
         let true_true_dest = true_map[&true_dest];
93107
         let true_val_map = build_value_map(func, lp, &true_blocks, &true_map);
94
-        let remapped_true_args: Vec<ValueId> = true_args.iter()
108
+        let remapped_true_args: Vec<ValueId> = true_args
109
+            .iter()
95110
             .map(|v| *true_val_map.get(v).unwrap_or(v))
96111
             .collect();
97112
         func.block_mut(true_cond_block).terminator =
@@ -102,7 +117,8 @@ fn unswitch_in_function(func: &mut Function) -> bool {
102117
         let false_cond_block = false_map[&cond_block];
103118
         let false_false_dest = false_map[&false_dest];
104119
         let false_val_map = build_value_map(func, lp, &false_blocks, &false_map);
105
-        let remapped_false_args: Vec<ValueId> = false_args.iter()
120
+        let remapped_false_args: Vec<ValueId> = false_args
121
+            .iter()
106122
             .map(|v| *false_val_map.get(v).unwrap_or(v))
107123
             .collect();
108124
         func.block_mut(false_cond_block).terminator =
@@ -147,14 +163,25 @@ fn find_unswitch_candidate(
147163
     for &bid in &lp.body {
148164
         let block = func.block(bid);
149165
         if let Some(Terminator::CondBranch {
150
-            cond, true_dest, true_args, false_dest, false_args,
151
-        }) = &block.terminator {
166
+            cond,
167
+            true_dest,
168
+            true_args,
169
+            false_dest,
170
+            false_args,
171
+        }) = &block.terminator
172
+        {
152173
             // Condition must be loop-invariant (not defined in the loop).
153174
             if !loop_defs.contains(cond) {
154175
                 // Both targets must be in the loop (not the loop exit).
155176
                 if lp.body.contains(true_dest) && lp.body.contains(false_dest) {
156
-                    return Some((bid, *cond, *true_dest, true_args.clone(),
157
-                                 *false_dest, false_args.clone()));
177
+                    return Some((
178
+                        bid,
179
+                        *cond,
180
+                        *true_dest,
181
+                        true_args.clone(),
182
+                        *false_dest,
183
+                        false_args.clone(),
184
+                    ));
158185
                 }
159186
             }
160187
         }
@@ -190,13 +217,17 @@ fn build_value_map(
190217
 #[cfg(test)]
191218
 mod tests {
192219
     use super::*;
193
-    use crate::ir::types::{IrType, IntWidth};
220
+    use crate::ir::types::{IntWidth, IrType};
221
+    use crate::lexer::{Position, Span};
194222
     use crate::opt::pass::Pass;
195
-    use crate::lexer::{Span, Position};
196223
 
197224
     fn span() -> Span {
198225
         let pos = Position { line: 0, col: 0 };
199
-        Span { file_id: 0, start: pos, end: pos }
226
+        Span {
227
+            file_id: 0,
228
+            start: pos,
229
+            end: pos,
230
+        }
200231
     }
201232
 
202233
     /// Build: entry → preheader → header(%i) → cmp → body → cond_branch(flag, t_body, f_body) →
@@ -208,32 +239,38 @@ mod tests {
208239
         let mut f = Function::new("test".into(), vec![], IrType::Void);
209240
 
210241
         let preheader = f.create_block("preheader");
211
-        let header    = f.create_block("header");
212
-        let cmp_blk   = f.create_block("cmp");
213
-        let body      = f.create_block("body");
214
-        let t_body    = f.create_block("t_body");
215
-        let f_body    = f.create_block("f_body");
216
-        let latch     = f.create_block("latch");
217
-        let exit      = f.create_block("exit");
218
-        let entry     = f.entry;
242
+        let header = f.create_block("header");
243
+        let cmp_blk = f.create_block("cmp");
244
+        let body = f.create_block("body");
245
+        let t_body = f.create_block("t_body");
246
+        let f_body = f.create_block("f_body");
247
+        let latch = f.create_block("latch");
248
+        let exit = f.create_block("exit");
249
+        let entry = f.entry;
219250
 
220251
         // Entry: flag = const_bool(true), c1 = const 1, c10 = const 10
221252
         let flag = f.next_value_id();
222253
         f.register_type(flag, IrType::Bool);
223254
         f.block_mut(entry).insts.push(Inst {
224
-            id: flag, ty: IrType::Bool, span: span(),
255
+            id: flag,
256
+            ty: IrType::Bool,
257
+            span: span(),
225258
             kind: InstKind::ConstBool(true),
226259
         });
227260
         let c1 = f.next_value_id();
228261
         f.register_type(c1, IrType::Int(IntWidth::I32));
229262
         f.block_mut(entry).insts.push(Inst {
230
-            id: c1, ty: IrType::Int(IntWidth::I32), span: span(),
263
+            id: c1,
264
+            ty: IrType::Int(IntWidth::I32),
265
+            span: span(),
231266
             kind: InstKind::ConstInt(1, IntWidth::I32),
232267
         });
233268
         let c10 = f.next_value_id();
234269
         f.register_type(c10, IrType::Int(IntWidth::I32));
235270
         f.block_mut(entry).insts.push(Inst {
236
-            id: c10, ty: IrType::Int(IntWidth::I32), span: span(),
271
+            id: c10,
272
+            ty: IrType::Int(IntWidth::I32),
273
+            span: span(),
237274
             kind: InstKind::ConstInt(10, IntWidth::I32),
238275
         });
239276
         f.block_mut(entry).terminator = Some(Terminator::Branch(preheader, vec![]));
@@ -244,27 +281,36 @@ mod tests {
244281
         // Header(%i) → cmp
245282
         let iv = f.next_value_id();
246283
         f.register_type(iv, IrType::Int(IntWidth::I32));
247
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
284
+        f.block_mut(header).params.push(BlockParam {
285
+            id: iv,
286
+            ty: IrType::Int(IntWidth::I32),
287
+        });
248288
         f.block_mut(header).terminator = Some(Terminator::Branch(cmp_blk, vec![]));
249289
 
250290
         // Cmp: icmp le %i, 10; condBr body, exit
251291
         let cmp_v = f.next_value_id();
252292
         f.register_type(cmp_v, IrType::Bool);
253293
         f.block_mut(cmp_blk).insts.push(Inst {
254
-            id: cmp_v, ty: IrType::Bool, span: span(),
294
+            id: cmp_v,
295
+            ty: IrType::Bool,
296
+            span: span(),
255297
             kind: InstKind::ICmp(CmpOp::Le, iv, c10),
256298
         });
257299
         f.block_mut(cmp_blk).terminator = Some(Terminator::CondBranch {
258300
             cond: cmp_v,
259
-            true_dest: body, true_args: vec![],
260
-            false_dest: exit, false_args: vec![],
301
+            true_dest: body,
302
+            true_args: vec![],
303
+            false_dest: exit,
304
+            false_args: vec![],
261305
         });
262306
 
263307
         // Body: condBr flag, t_body, f_body  ← the unswitchable conditional
264308
         f.block_mut(body).terminator = Some(Terminator::CondBranch {
265309
             cond: flag,
266
-            true_dest: t_body, true_args: vec![],
267
-            false_dest: f_body, false_args: vec![],
310
+            true_dest: t_body,
311
+            true_args: vec![],
312
+            false_dest: f_body,
313
+            false_args: vec![],
268314
         });
269315
 
270316
         // t_body → latch
@@ -277,7 +323,9 @@ mod tests {
277323
         let nxt = f.next_value_id();
278324
         f.register_type(nxt, IrType::Int(IntWidth::I32));
279325
         f.block_mut(latch).insts.push(Inst {
280
-            id: nxt, ty: IrType::Int(IntWidth::I32), span: span(),
326
+            id: nxt,
327
+            ty: IrType::Int(IntWidth::I32),
328
+            span: span(),
281329
             kind: InstKind::IAdd(iv, c1),
282330
         });
283331
         f.block_mut(latch).terminator = Some(Terminator::Branch(header, vec![nxt]));
@@ -298,10 +346,15 @@ mod tests {
298346
 
299347
         // After unswitching, the preheader should have a CondBranch (not a Branch).
300348
         let f = &m.functions[0];
301
-        let preheader = f.blocks.iter().find(|b| b.name.contains("preheader")).unwrap();
349
+        let preheader = f
350
+            .blocks
351
+            .iter()
352
+            .find(|b| b.name.contains("preheader"))
353
+            .unwrap();
302354
         assert!(
303355
             matches!(&preheader.terminator, Some(Terminator::CondBranch { .. })),
304
-            "preheader should now have a CondBranch: {:?}", preheader.terminator
356
+            "preheader should now have a CondBranch: {:?}",
357
+            preheader.terminator
305358
         );
306359
     }
307360
 
@@ -321,49 +374,66 @@ mod tests {
321374
         let c1 = f.next_value_id();
322375
         f.register_type(c1, IrType::Int(IntWidth::I32));
323376
         f.block_mut(entry).insts.push(Inst {
324
-            id: c1, ty: IrType::Int(IntWidth::I32), span: span(),
377
+            id: c1,
378
+            ty: IrType::Int(IntWidth::I32),
379
+            span: span(),
325380
             kind: InstKind::ConstInt(1, IntWidth::I32),
326381
         });
327382
         let c10 = f.next_value_id();
328383
         f.register_type(c10, IrType::Int(IntWidth::I32));
329384
         f.block_mut(entry).insts.push(Inst {
330
-            id: c10, ty: IrType::Int(IntWidth::I32), span: span(),
385
+            id: c10,
386
+            ty: IrType::Int(IntWidth::I32),
387
+            span: span(),
331388
             kind: InstKind::ConstInt(10, IntWidth::I32),
332389
         });
333390
         f.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![c1]));
334391
 
335392
         let iv = f.next_value_id();
336393
         f.register_type(iv, IrType::Int(IntWidth::I32));
337
-        f.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
394
+        f.block_mut(header).params.push(BlockParam {
395
+            id: iv,
396
+            ty: IrType::Int(IntWidth::I32),
397
+        });
338398
         let cmp_v = f.next_value_id();
339399
         f.register_type(cmp_v, IrType::Bool);
340400
         f.block_mut(header).insts.push(Inst {
341
-            id: cmp_v, ty: IrType::Bool, span: span(),
401
+            id: cmp_v,
402
+            ty: IrType::Bool,
403
+            span: span(),
342404
             kind: InstKind::ICmp(CmpOp::Le, iv, c10),
343405
         });
344406
         f.block_mut(header).terminator = Some(Terminator::CondBranch {
345407
             cond: cmp_v,
346
-            true_dest: body, true_args: vec![],
347
-            false_dest: exit, false_args: vec![],
408
+            true_dest: body,
409
+            true_args: vec![],
410
+            false_dest: exit,
411
+            false_args: vec![],
348412
         });
349413
 
350414
         // Body: the "conditional" uses the IV (loop-variant).
351415
         let iv_cmp = f.next_value_id();
352416
         f.register_type(iv_cmp, IrType::Bool);
353417
         f.block_mut(body).insts.push(Inst {
354
-            id: iv_cmp, ty: IrType::Bool, span: span(),
418
+            id: iv_cmp,
419
+            ty: IrType::Bool,
420
+            span: span(),
355421
             kind: InstKind::ICmp(CmpOp::Le, iv, c1),
356422
         });
357423
         f.block_mut(body).terminator = Some(Terminator::CondBranch {
358424
             cond: iv_cmp,
359
-            true_dest: latch, true_args: vec![],
360
-            false_dest: latch, false_args: vec![],
425
+            true_dest: latch,
426
+            true_args: vec![],
427
+            false_dest: latch,
428
+            false_args: vec![],
361429
         });
362430
 
363431
         let nxt = f.next_value_id();
364432
         f.register_type(nxt, IrType::Int(IntWidth::I32));
365433
         f.block_mut(latch).insts.push(Inst {
366
-            id: nxt, ty: IrType::Int(IntWidth::I32), span: span(),
434
+            id: nxt,
435
+            ty: IrType::Int(IntWidth::I32),
436
+            span: span(),
367437
             kind: InstKind::IAdd(iv, c1),
368438
         });
369439
         f.block_mut(latch).terminator = Some(Terminator::Branch(header, vec![nxt]));
src/opt/util.rsmodified
22 lines changed — click to load
@@ -14,18 +14,8 @@
1414
 // flagged it as dead code from this module's perspective.
1515
 #[allow(unused_imports)]
1616
 pub use crate::ir::walk::{
17
-    inst_uses,
18
-    terminator_uses,
19
-    terminator_targets,
20
-    for_each_operand_mut,
21
-    for_each_terminator_operand_mut,
22
-    substitute_uses,
23
-    predecessors,
24
-    compute_dominators,
25
-    compute_immediate_dominators,
26
-    dominator_tree_children,
27
-    compute_dominance_frontiers,
28
-    find_natural_loops,
29
-    NaturalLoop,
30
-    prune_unreachable,
17
+    compute_dominance_frontiers, compute_dominators, compute_immediate_dominators,
18
+    dominator_tree_children, find_natural_loops, for_each_operand_mut,
19
+    for_each_terminator_operand_mut, inst_uses, predecessors, prune_unreachable, substitute_uses,
20
+    terminator_targets, terminator_uses, NaturalLoop,
3121
 };
src/opt/vectorize.rsmodified
320 lines changed — click to load
@@ -20,7 +20,9 @@ use super::util::{find_natural_loops, inst_uses, predecessors, terminator_uses,
2020
 pub struct Vectorize;
2121
 
2222
 impl Pass for Vectorize {
23
-    fn name(&self) -> &'static str { "vectorize" }
23
+    fn name(&self) -> &'static str {
24
+        "vectorize"
25
+    }
2426
 
2527
     fn run(&self, module: &mut Module) -> bool {
2628
         let mut changed = false;
@@ -164,14 +166,20 @@ fn detect_counted_loop(
164166
         }) => (*cond, *true_dest, *false_dest, true_args, false_args),
165167
         _ => return None,
166168
     };
167
-    if !true_args.is_empty() || !false_args.is_empty() || true_dest != body || lp.body.contains(&false_dest) {
169
+    if !true_args.is_empty()
170
+        || !false_args.is_empty()
171
+        || true_dest != body
172
+        || lp.body.contains(&false_dest)
173
+    {
168174
         return None;
169175
     }
170176
 
171177
     let cond_inst = header_block.insts.iter().find(|inst| inst.id == cond_id)?;
172178
     let iv_bound = match cond_inst.kind {
173179
         InstKind::ICmp(CmpOp::Le, lhs, rhs) if lhs == iv_param => resolve_const_int(func, rhs)?,
174
-        InstKind::ICmp(CmpOp::Lt, lhs, rhs) if lhs == iv_param => resolve_const_int(func, rhs)?.checked_sub(1)?,
180
+        InstKind::ICmp(CmpOp::Lt, lhs, rhs) if lhs == iv_param => {
181
+            resolve_const_int(func, rhs)?.checked_sub(1)?
182
+        }
175183
         _ => return None,
176184
     };
177185
 
@@ -231,13 +239,10 @@ fn build_kernel_plan(
231239
         return None;
232240
     }
233241
 
234
-    let mut stores = body
235
-        .insts
236
-        .iter()
237
-        .filter_map(|inst| match inst.kind {
238
-            InstKind::Store(value, ptr) => Some((inst.span, value, ptr)),
239
-            _ => None,
240
-        });
242
+    let mut stores = body.insts.iter().filter_map(|inst| match inst.kind {
243
+        InstKind::Store(value, ptr) => Some((inst.span, value, ptr)),
244
+        _ => None,
245
+    });
241246
     let (span, stored_value, dest_ptr) = stores.next()?;
242247
     if stores.next().is_some() {
243248
         return None;
@@ -248,7 +253,9 @@ fn build_kernel_plan(
248253
         return None;
249254
     }
250255
 
251
-    let plan = if let Some(scalar) = classify_invariant_scalar(func, loop_defs, stored_value, &dest.elem_ty) {
256
+    let plan = if let Some(scalar) =
257
+        classify_invariant_scalar(func, loop_defs, stored_value, &dest.elem_ty)
258
+    {
252259
         let kernel = fill_kernel_name(&dest.elem_ty)?;
253260
         KernelPlan::Fill {
254261
             kernel,
@@ -382,7 +389,11 @@ fn classify_invariant_scalar(
382389
     (func.value_type(value).as_ref() == Some(elem_ty)).then_some(value)
383390
 }
384391
 
385
-fn classify_loaded_array(func: &Function, value: ValueId, iv_param: ValueId) -> Option<ArrayAccess> {
392
+fn classify_loaded_array(
393
+    func: &Function,
394
+    value: ValueId,
395
+    iv_param: ValueId,
396
+) -> Option<ArrayAccess> {
386397
     let defs = inst_map(func);
387398
     let inst = defs.get(&value)?;
388399
     let InstKind::Load(ptr) = inst.kind else {
@@ -442,18 +453,18 @@ fn loop_values_escape(func: &Function, lp: &NaturalLoop, loop_defs: &HashSet<Val
442453
         if lp.body.contains(&block.id) {
443454
             continue;
444455
         }
445
-        if block
446
-            .insts
447
-            .iter()
448
-            .any(|inst| inst_uses(&inst.kind).into_iter().any(|value| loop_defs.contains(&value)))
449
-        {
456
+        if block.insts.iter().any(|inst| {
457
+            inst_uses(&inst.kind)
458
+                .into_iter()
459
+                .any(|value| loop_defs.contains(&value))
460
+        }) {
450461
             return true;
451462
         }
452
-        if block
453
-            .terminator
454
-            .as_ref()
455
-            .is_some_and(|term| terminator_uses(term).into_iter().any(|value| loop_defs.contains(&value)))
456
-        {
463
+        if block.terminator.as_ref().is_some_and(|term| {
464
+            terminator_uses(term)
465
+                .into_iter()
466
+                .any(|value| loop_defs.contains(&value))
467
+        }) {
457468
             return true;
458469
         }
459470
     }
@@ -468,14 +479,33 @@ fn apply_kernel_plan(
468479
 ) {
469480
     let n_id = ensure_i64_const(func, shape.preheader, kernel_len(plan) as i64, span);
470481
     let (kernel, args) = match plan {
471
-        KernelPlan::Fill { kernel, dest, scalar, .. } => (kernel, vec![dest, n_id, scalar]),
472
-        KernelPlan::ArrayBinary { kernel, dest, lhs, rhs, .. } => (kernel, vec![dest, lhs, rhs, n_id]),
473
-        KernelPlan::ArrayScalar { kernel, dest, src, scalar, .. } => {
474
-            (kernel, vec![dest, src, scalar, n_id])
475
-        }
476
-        KernelPlan::ScalarArray { kernel, dest, scalar, src, .. } => {
477
-            (kernel, vec![dest, scalar, src, n_id])
478
-        }
482
+        KernelPlan::Fill {
483
+            kernel,
484
+            dest,
485
+            scalar,
486
+            ..
487
+        } => (kernel, vec![dest, n_id, scalar]),
488
+        KernelPlan::ArrayBinary {
489
+            kernel,
490
+            dest,
491
+            lhs,
492
+            rhs,
493
+            ..
494
+        } => (kernel, vec![dest, lhs, rhs, n_id]),
495
+        KernelPlan::ArrayScalar {
496
+            kernel,
497
+            dest,
498
+            src,
499
+            scalar,
500
+            ..
501
+        } => (kernel, vec![dest, src, scalar, n_id]),
502
+        KernelPlan::ScalarArray {
503
+            kernel,
504
+            dest,
505
+            scalar,
506
+            src,
507
+            ..
508
+        } => (kernel, vec![dest, scalar, src, n_id]),
479509
     };
480510
 
481511
     let id = func.next_value_id();
@@ -579,18 +609,27 @@ fn scalar_array_kernel_name(kind: BinaryKind, ty: &IrType) -> Option<&'static st
579609
 mod tests {
580610
     use super::*;
581611
     use crate::ir::types::IrType;
582
-    use crate::opt::pass::Pass;
583612
     use crate::lexer::{Position, Span};
613
+    use crate::opt::pass::Pass;
584614
 
585615
     fn dummy_span() -> Span {
586616
         let p = Position { line: 0, col: 0 };
587
-        Span { file_id: 0, start: p, end: p }
617
+        Span {
618
+            file_id: 0,
619
+            start: p,
620
+            end: p,
621
+        }
588622
     }
589623
 
590624
     fn push_inst(func: &mut Function, block: BlockId, kind: InstKind, ty: IrType) -> ValueId {
591625
         let id = func.next_value_id();
592626
         func.register_type(id, ty.clone());
593
-        func.block_mut(block).insts.push(Inst { id, kind, ty, span: dummy_span() });
627
+        func.block_mut(block).insts.push(Inst {
628
+            id,
629
+            kind,
630
+            ty,
631
+            span: dummy_span(),
632
+        });
594633
         id
595634
     }
596635
 
@@ -608,29 +647,61 @@ mod tests {
608647
             &mut func,
609648
             entry,
610649
             InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32)),
611
-            IrType::Ptr(Box::new(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32))),
650
+            IrType::Ptr(Box::new(IrType::Array(
651
+                Box::new(IrType::Int(IntWidth::I32)),
652
+                32,
653
+            ))),
612654
         );
613655
         let b = push_inst(
614656
             &mut func,
615657
             entry,
616658
             InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32)),
617
-            IrType::Ptr(Box::new(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32))),
659
+            IrType::Ptr(Box::new(IrType::Array(
660
+                Box::new(IrType::Int(IntWidth::I32)),
661
+                32,
662
+            ))),
618663
         );
619664
         let c = push_inst(
620665
             &mut func,
621666
             entry,
622667
             InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32)),
623
-            IrType::Ptr(Box::new(IrType::Array(Box::new(IrType::Int(IntWidth::I32)), 32))),
668
+            IrType::Ptr(Box::new(IrType::Array(
669
+                Box::new(IrType::Int(IntWidth::I32)),
670
+                32,
671
+            ))),
672
+        );
673
+        let one_i32 = push_inst(
674
+            &mut func,
675
+            entry,
676
+            InstKind::ConstInt(1, IntWidth::I32),
677
+            IrType::Int(IntWidth::I32),
678
+        );
679
+        let hi_i32 = push_inst(
680
+            &mut func,
681
+            entry,
682
+            InstKind::ConstInt(32, IntWidth::I32),
683
+            IrType::Int(IntWidth::I32),
684
+        );
685
+        let one_i64 = push_inst(
686
+            &mut func,
687
+            entry,
688
+            InstKind::ConstInt(1, IntWidth::I64),
689
+            IrType::Int(IntWidth::I64),
624690
         );
625
-        let one_i32 = push_inst(&mut func, entry, InstKind::ConstInt(1, IntWidth::I32), IrType::Int(IntWidth::I32));
626
-        let hi_i32 = push_inst(&mut func, entry, InstKind::ConstInt(32, IntWidth::I32), IrType::Int(IntWidth::I32));
627
-        let one_i64 = push_inst(&mut func, entry, InstKind::ConstInt(1, IntWidth::I64), IrType::Int(IntWidth::I64));
628691
         func.block_mut(entry).terminator = Some(Terminator::Branch(header, vec![one_i32]));
629692
 
630693
         let iv = func.next_value_id();
631694
         func.register_type(iv, IrType::Int(IntWidth::I32));
632
-        func.block_mut(header).params.push(BlockParam { id: iv, ty: IrType::Int(IntWidth::I32) });
633
-        let cmp = push_inst(&mut func, header, InstKind::ICmp(CmpOp::Le, iv, hi_i32), IrType::Bool);
695
+        func.block_mut(header).params.push(BlockParam {
696
+            id: iv,
697
+            ty: IrType::Int(IntWidth::I32),
698
+        });
699
+        let cmp = push_inst(
700
+            &mut func,
701
+            header,
702
+            InstKind::ICmp(CmpOp::Le, iv, hi_i32),
703
+            IrType::Bool,
704
+        );
634705
         func.block_mut(header).terminator = Some(Terminator::CondBranch {
635706
             cond: cmp,
636707
             true_dest: body,
@@ -639,23 +710,71 @@ mod tests {
639710
             false_args: vec![],
640711
         });
641712
 
642
-        let idx64 = push_inst(&mut func, body, InstKind::IntExtend(iv, IntWidth::I64, true), IrType::Int(IntWidth::I64));
643
-        let offset = push_inst(&mut func, body, InstKind::ISub(idx64, one_i64), IrType::Int(IntWidth::I64));
644
-        let a_ptr = push_inst(&mut func, body, InstKind::GetElementPtr(a, vec![offset]), IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
645
-        let a_val = push_inst(&mut func, body, InstKind::Load(a_ptr), IrType::Int(IntWidth::I32));
646
-        let b_ptr = push_inst(&mut func, body, InstKind::GetElementPtr(b, vec![offset]), IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
647
-        let b_val = push_inst(&mut func, body, InstKind::Load(b_ptr), IrType::Int(IntWidth::I32));
648
-        let sum = push_inst(&mut func, body, InstKind::IAdd(a_val, b_val), IrType::Int(IntWidth::I32));
649
-        let c_ptr = push_inst(&mut func, body, InstKind::GetElementPtr(c, vec![offset]), IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
713
+        let idx64 = push_inst(
714
+            &mut func,
715
+            body,
716
+            InstKind::IntExtend(iv, IntWidth::I64, true),
717
+            IrType::Int(IntWidth::I64),
718
+        );
719
+        let offset = push_inst(
720
+            &mut func,
721
+            body,
722
+            InstKind::ISub(idx64, one_i64),
723
+            IrType::Int(IntWidth::I64),
724
+        );
725
+        let a_ptr = push_inst(
726
+            &mut func,
727
+            body,
728
+            InstKind::GetElementPtr(a, vec![offset]),
729
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
730
+        );
731
+        let a_val = push_inst(
732
+            &mut func,
733
+            body,
734
+            InstKind::Load(a_ptr),
735
+            IrType::Int(IntWidth::I32),
736
+        );
737
+        let b_ptr = push_inst(
738
+            &mut func,
739
+            body,
740
+            InstKind::GetElementPtr(b, vec![offset]),
741
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
742
+        );
743
+        let b_val = push_inst(
744
+            &mut func,
745
+            body,
746
+            InstKind::Load(b_ptr),
747
+            IrType::Int(IntWidth::I32),
748
+        );
749
+        let sum = push_inst(
750
+            &mut func,
751
+            body,
752
+            InstKind::IAdd(a_val, b_val),
753
+            IrType::Int(IntWidth::I32),
754
+        );
755
+        let c_ptr = push_inst(
756
+            &mut func,
757
+            body,
758
+            InstKind::GetElementPtr(c, vec![offset]),
759
+            IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
760
+        );
650761
         push_inst(&mut func, body, InstKind::Store(sum, c_ptr), IrType::Void);
651
-        let next = push_inst(&mut func, body, InstKind::IAdd(iv, one_i32), IrType::Int(IntWidth::I32));
762
+        let next = push_inst(
763
+            &mut func,
764
+            body,
765
+            InstKind::IAdd(iv, one_i32),
766
+            IrType::Int(IntWidth::I32),
767
+        );
652768
         func.block_mut(body).terminator = Some(Terminator::Branch(header, vec![next]));
653769
         func.block_mut(exit).terminator = Some(Terminator::Return(None));
654770
 
655771
         module.add_function(func);
656772
 
657773
         let changed = Vectorize.run(&mut module);
658
-        assert!(changed, "vectorize should rewrite the counted array-add loop");
774
+        assert!(
775
+            changed,
776
+            "vectorize should rewrite the counted array-add loop"
777
+        );
659778
 
660779
         let func = &module.functions[0];
661780
         let entry_block = func.block(entry);
src/parser/decl.rsmodified
1041 lines changed — click to load
@@ -3,10 +3,10 @@
33
 //! Parses type declarations, USE statements, IMPLICIT, derived type
44
 //! definitions, and legacy declaration forms (COMMON, DATA, etc.).
55
 
6
-use crate::ast::Spanned;
6
+use super::{ParseError, Parser};
77
 use crate::ast::decl::*;
8
+use crate::ast::Spanned;
89
 use crate::lexer::TokenKind;
9
-use super::{Parser, ParseError};
1010
 
1111
 impl<'a> Parser<'a> {
1212
     // ---- Type specifier parsing ----
@@ -15,8 +15,14 @@ impl<'a> Parser<'a> {
1515
     pub fn try_parse_type_spec(&mut self) -> Option<Result<TypeSpec, ParseError>> {
1616
         let text = self.peek_text().to_lowercase();
1717
         match text.as_str() {
18
-            "integer" => { self.advance(); Some(self.parse_kind_selector().map(TypeSpec::Integer)) }
19
-            "real" => { self.advance(); Some(self.parse_kind_selector().map(TypeSpec::Real)) }
18
+            "integer" => {
19
+                self.advance();
20
+                Some(self.parse_kind_selector().map(TypeSpec::Integer))
21
+            }
22
+            "real" => {
23
+                self.advance();
24
+                Some(self.parse_kind_selector().map(TypeSpec::Real))
25
+            }
2026
             "doubleprecision" | "double" => {
2127
                 self.advance();
2228
                 // Handle "double precision" / "double complex" as two tokens.
@@ -30,10 +36,22 @@ impl<'a> Parser<'a> {
3036
                     Some(Ok(TypeSpec::DoublePrecision))
3137
                 }
3238
             }
33
-            "complex" => { self.advance(); Some(self.parse_kind_selector().map(TypeSpec::Complex)) }
34
-            "doublecomplex" => { self.advance(); Some(Ok(TypeSpec::DoubleComplex)) }
35
-            "logical" => { self.advance(); Some(self.parse_kind_selector().map(TypeSpec::Logical)) }
36
-            "character" => { self.advance(); Some(self.parse_char_selector().map(TypeSpec::Character)) }
39
+            "complex" => {
40
+                self.advance();
41
+                Some(self.parse_kind_selector().map(TypeSpec::Complex))
42
+            }
43
+            "doublecomplex" => {
44
+                self.advance();
45
+                Some(Ok(TypeSpec::DoubleComplex))
46
+            }
47
+            "logical" => {
48
+                self.advance();
49
+                Some(self.parse_kind_selector().map(TypeSpec::Logical))
50
+            }
51
+            "character" => {
52
+                self.advance();
53
+                Some(self.parse_char_selector().map(TypeSpec::Character))
54
+            }
3755
             "type" => {
3856
                 // type(name) is a type specifier, but type :: name is a derived type definition.
3957
                 // Only consume if followed by (.
@@ -58,8 +76,14 @@ impl<'a> Parser<'a> {
5876
     fn parse_implicit_type_spec(&mut self) -> Option<Result<TypeSpec, ParseError>> {
5977
         let text = self.peek_text().to_lowercase();
6078
         match text.as_str() {
61
-            "integer" => { self.advance(); Some(Ok(TypeSpec::Integer(None))) }
62
-            "real" => { self.advance(); Some(Ok(TypeSpec::Real(None))) }
79
+            "integer" => {
80
+                self.advance();
81
+                Some(Ok(TypeSpec::Integer(None)))
82
+            }
83
+            "real" => {
84
+                self.advance();
85
+                Some(Ok(TypeSpec::Real(None)))
86
+            }
6387
             "doubleprecision" | "double" => {
6488
                 self.advance();
6589
                 if self.peek_text().eq_ignore_ascii_case("precision") {
@@ -72,9 +96,18 @@ impl<'a> Parser<'a> {
7296
                     Some(Ok(TypeSpec::DoublePrecision))
7397
                 }
7498
             }
75
-            "complex" => { self.advance(); Some(Ok(TypeSpec::Complex(None))) }
76
-            "logical" => { self.advance(); Some(Ok(TypeSpec::Logical(None))) }
77
-            "character" => { self.advance(); Some(Ok(TypeSpec::Character(None))) }
99
+            "complex" => {
100
+                self.advance();
101
+                Some(Ok(TypeSpec::Complex(None)))
102
+            }
103
+            "logical" => {
104
+                self.advance();
105
+                Some(Ok(TypeSpec::Logical(None)))
106
+            }
107
+            "character" => {
108
+                self.advance();
109
+                Some(Ok(TypeSpec::Character(None)))
110
+            }
78111
             _ => None,
79112
         }
80113
     }
@@ -90,7 +123,7 @@ impl<'a> Parser<'a> {
90123
             return Ok(None);
91124
         }
92125
         self.advance(); // (
93
-        // Check for kind= keyword
126
+                        // Check for kind= keyword
94127
         if self.peek_text().eq_ignore_ascii_case("kind") {
95128
             let next_pos = self.pos + 1;
96129
             if next_pos < self.tokens.len() && self.tokens[next_pos].kind == TokenKind::Assign {
@@ -107,7 +140,10 @@ impl<'a> Parser<'a> {
107140
         // Check for *N (old-style)
108141
         if self.eat(&TokenKind::Star) {
109142
             let len = self.parse_len_spec()?;
110
-            return Ok(Some(CharSelector { len: Some(len), kind: None }));
143
+            return Ok(Some(CharSelector {
144
+                len: Some(len),
145
+                kind: None,
146
+            }));
111147
         }
112148
         if self.peek() != &TokenKind::LParen {
113149
             return Ok(None);
@@ -185,7 +221,11 @@ impl<'a> Parser<'a> {
185221
         self.expect(&TokenKind::LParen)?;
186222
         if self.eat(&TokenKind::Star) {
187223
             self.expect(&TokenKind::RParen)?;
188
-            return Ok(if is_class { TypeSpec::ClassStar } else { TypeSpec::TypeStar });
224
+            return Ok(if is_class {
225
+                TypeSpec::ClassStar
226
+            } else {
227
+                TypeSpec::TypeStar
228
+            });
189229
         }
190230
         if self.peek() != &TokenKind::Identifier {
191231
             return Err(self.error(format!("expected type name, got {}", self.peek())));
@@ -193,7 +233,11 @@ impl<'a> Parser<'a> {
193233
         let name_tok = self.advance().clone();
194234
         let name = name_tok.text;
195235
         self.expect(&TokenKind::RParen)?;
196
-        Ok(if is_class { TypeSpec::Class(name) } else { TypeSpec::Type(name) })
236
+        Ok(if is_class {
237
+            TypeSpec::Class(name)
238
+        } else {
239
+            TypeSpec::Type(name)
240
+        })
197241
     }
198242
 
199243
     // ---- Attribute parsing ----
@@ -202,21 +246,66 @@ impl<'a> Parser<'a> {
202246
     pub fn try_parse_attribute(&mut self) -> Option<Result<Attribute, ParseError>> {
203247
         let text = self.peek_text().to_lowercase();
204248
         match text.as_str() {
205
-            "allocatable" => { self.advance(); Some(Ok(Attribute::Allocatable)) }
206
-            "pointer" => { self.advance(); Some(Ok(Attribute::Pointer)) }
207
-            "target" => { self.advance(); Some(Ok(Attribute::Target)) }
208
-            "optional" => { self.advance(); Some(Ok(Attribute::Optional)) }
209
-            "save" => { self.advance(); Some(Ok(Attribute::Save)) }
210
-            "parameter" => { self.advance(); Some(Ok(Attribute::Parameter)) }
211
-            "value" => { self.advance(); Some(Ok(Attribute::Value)) }
212
-            "volatile" => { self.advance(); Some(Ok(Attribute::Volatile)) }
213
-            "asynchronous" => { self.advance(); Some(Ok(Attribute::Asynchronous)) }
214
-            "protected" => { self.advance(); Some(Ok(Attribute::Protected)) }
215
-            "contiguous" => { self.advance(); Some(Ok(Attribute::Contiguous)) }
216
-            "external" => { self.advance(); Some(Ok(Attribute::External)) }
217
-            "intrinsic" => { self.advance(); Some(Ok(Attribute::Intrinsic)) }
218
-            "public" => { self.advance(); Some(Ok(Attribute::Public)) }
219
-            "private" => { self.advance(); Some(Ok(Attribute::Private)) }
249
+            "allocatable" => {
250
+                self.advance();
251
+                Some(Ok(Attribute::Allocatable))
252
+            }
253
+            "pointer" => {
254
+                self.advance();
255
+                Some(Ok(Attribute::Pointer))
256
+            }
257
+            "target" => {
258
+                self.advance();
259
+                Some(Ok(Attribute::Target))
260
+            }
261
+            "optional" => {
262
+                self.advance();
263
+                Some(Ok(Attribute::Optional))
264
+            }
265
+            "save" => {
266
+                self.advance();
267
+                Some(Ok(Attribute::Save))
268
+            }
269
+            "parameter" => {
270
+                self.advance();
271
+                Some(Ok(Attribute::Parameter))
272
+            }
273
+            "value" => {
274
+                self.advance();
275
+                Some(Ok(Attribute::Value))
276
+            }
277
+            "volatile" => {
278
+                self.advance();
279
+                Some(Ok(Attribute::Volatile))
280
+            }
281
+            "asynchronous" => {
282
+                self.advance();
283
+                Some(Ok(Attribute::Asynchronous))
284
+            }
285
+            "protected" => {
286
+                self.advance();
287
+                Some(Ok(Attribute::Protected))
288
+            }
289
+            "contiguous" => {
290
+                self.advance();
291
+                Some(Ok(Attribute::Contiguous))
292
+            }
293
+            "external" => {
294
+                self.advance();
295
+                Some(Ok(Attribute::External))
296
+            }
297
+            "intrinsic" => {
298
+                self.advance();
299
+                Some(Ok(Attribute::Intrinsic))
300
+            }
301
+            "public" => {
302
+                self.advance();
303
+                Some(Ok(Attribute::Public))
304
+            }
305
+            "private" => {
306
+                self.advance();
307
+                Some(Ok(Attribute::Private))
308
+            }
220309
             "dimension" => {
221310
                 self.advance();
222311
                 Some(self.parse_dimension_spec().map(Attribute::Dimension))
@@ -244,7 +333,9 @@ impl<'a> Parser<'a> {
244333
         let mut specs = Vec::new();
245334
         loop {
246335
             specs.push(self.parse_one_array_spec()?);
247
-            if !self.eat(&TokenKind::Comma) { break; }
336
+            if !self.eat(&TokenKind::Comma) {
337
+                break;
338
+            }
248339
         }
249340
         Ok(specs)
250341
     }
@@ -289,11 +380,17 @@ impl<'a> Parser<'a> {
289380
                 return Ok(ArraySpec::AssumedShape { lower: Some(first) });
290381
             }
291382
             let upper = self.parse_expr()?;
292
-            return Ok(ArraySpec::Explicit { lower: Some(first), upper });
383
+            return Ok(ArraySpec::Explicit {
384
+                lower: Some(first),
385
+                upper,
386
+            });
293387
         }
294388
 
295389
         // Just an upper bound (lower is 1 implicitly).
296
-        Ok(ArraySpec::Explicit { lower: None, upper: first })
390
+        Ok(ArraySpec::Explicit {
391
+            lower: None,
392
+            upper: first,
393
+        })
297394
     }
298395
 
299396
     fn parse_intent_spec(&mut self) -> Result<Intent, ParseError> {
@@ -309,9 +406,20 @@ impl<'a> Parser<'a> {
309406
                     Intent::In
310407
                 }
311408
             }
312
-            "out" => { self.advance(); Intent::Out }
313
-            "inout" => { self.advance(); Intent::InOut }
314
-            _ => return Err(self.error(format!("expected intent specifier, got {}", self.peek_text()))),
409
+            "out" => {
410
+                self.advance();
411
+                Intent::Out
412
+            }
413
+            "inout" => {
414
+                self.advance();
415
+                Intent::InOut
416
+            }
417
+            _ => {
418
+                return Err(self.error(format!(
419
+                    "expected intent specifier, got {}",
420
+                    self.peek_text()
421
+                )))
422
+            }
315423
         };
316424
         self.expect(&TokenKind::RParen)?;
317425
         Ok(intent)
@@ -370,14 +478,23 @@ impl<'a> Parser<'a> {
370478
         let entities = self.parse_entity_list()?;
371479
 
372480
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
373
-        Ok(Spanned::new(Decl::TypeDecl { type_spec, attrs, entities }, span))
481
+        Ok(Spanned::new(
482
+            Decl::TypeDecl {
483
+                type_spec,
484
+                attrs,
485
+                entities,
486
+            },
487
+            span,
488
+        ))
374489
     }
375490
 
376491
     fn parse_entity_list(&mut self) -> Result<Vec<EntityDecl>, ParseError> {
377492
         let mut entities = Vec::new();
378493
         loop {
379494
             entities.push(self.parse_entity_decl()?);
380
-            if !self.eat(&TokenKind::Comma) { break; }
495
+            if !self.eat(&TokenKind::Comma) {
496
+                break;
497
+            }
381498
         }
382499
         Ok(entities)
383500
     }
@@ -401,7 +518,7 @@ impl<'a> Parser<'a> {
401518
 
402519
         if self.peek() == &TokenKind::LBracket {
403520
             return Err(
404
-                self.error("coarray declarations are recognized but not yet implemented".into()),
521
+                self.error("coarray declarations are recognized but not yet implemented".into())
405522
             );
406523
         }
407524
 
@@ -426,7 +543,13 @@ impl<'a> Parser<'a> {
426543
             None
427544
         };
428545
 
429
-        Ok(EntityDecl { name, array_spec, char_len, init, ptr_init })
546
+        Ok(EntityDecl {
547
+            name,
548
+            array_spec,
549
+            char_len,
550
+            init,
551
+            ptr_init,
552
+        })
430553
     }
431554
 
432555
     // ---- USE statement ----
@@ -471,21 +594,36 @@ impl<'a> Parser<'a> {
471594
         }
472595
 
473596
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
474
-        Ok(Spanned::new(Decl::UseStmt { module, nature, renames, only }, span))
597
+        Ok(Spanned::new(
598
+            Decl::UseStmt {
599
+                module,
600
+                nature,
601
+                renames,
602
+                only,
603
+            },
604
+            span,
605
+        ))
475606
     }
476607
 
477608
     fn parse_only_list(&mut self) -> Result<Vec<OnlyItem>, ParseError> {
478609
         let mut items = Vec::new();
479
-        if self.at_stmt_end() { return Ok(items); }
610
+        if self.at_stmt_end() {
611
+            return Ok(items);
612
+        }
480613
         loop {
481614
             let name = self.advance().clone().text;
482615
             if self.eat(&TokenKind::Arrow) {
483616
                 let remote = self.advance().clone().text;
484
-                items.push(OnlyItem::Rename(Rename { local: name, remote }));
617
+                items.push(OnlyItem::Rename(Rename {
618
+                    local: name,
619
+                    remote,
620
+                }));
485621
             } else {
486622
                 items.push(OnlyItem::Name(name));
487623
             }
488
-            if !self.eat(&TokenKind::Comma) { break; }
624
+            if !self.eat(&TokenKind::Comma) {
625
+                break;
626
+            }
489627
         }
490628
         Ok(items)
491629
     }
@@ -497,7 +635,9 @@ impl<'a> Parser<'a> {
497635
             self.expect(&TokenKind::Arrow)?;
498636
             let remote = self.advance().clone().text;
499637
             renames.push(Rename { local, remote });
500
-            if !self.eat(&TokenKind::Comma) { break; }
638
+            if !self.eat(&TokenKind::Comma) {
639
+                break;
640
+            }
501641
         }
502642
         Ok(renames)
503643
     }
@@ -519,11 +659,19 @@ impl<'a> Parser<'a> {
519659
                 loop {
520660
                     let spec = self.peek_text().to_lowercase();
521661
                     match spec.as_str() {
522
-                        "type" => { self.advance(); type_ = true; }
523
-                        "external" => { self.advance(); external = true; }
662
+                        "type" => {
663
+                            self.advance();
664
+                            type_ = true;
665
+                        }
666
+                        "external" => {
667
+                            self.advance();
668
+                            external = true;
669
+                        }
524670
                         _ => break,
525671
                     }
526
-                    if !self.eat(&TokenKind::Comma) { break; }
672
+                    if !self.eat(&TokenKind::Comma) {
673
+                        break;
674
+                    }
527675
                 }
528676
                 self.expect(&TokenKind::RParen)?;
529677
             }
@@ -538,7 +686,8 @@ impl<'a> Parser<'a> {
538686
         // is a letter range, not kind=i-n.
539687
         let mut specs = Vec::new();
540688
         loop {
541
-            let type_spec = self.parse_implicit_type_spec()
689
+            let type_spec = self
690
+                .parse_implicit_type_spec()
542691
                 .ok_or_else(|| self.error("expected type specifier in IMPLICIT".into()))??;
543692
             self.expect(&TokenKind::LParen)?;
544693
             let mut ranges = Vec::new();
@@ -547,11 +696,15 @@ impl<'a> Parser<'a> {
547696
                 self.expect(&TokenKind::Minus)?;
548697
                 let end_letter = self.advance().clone().text.chars().next().unwrap_or('z');
549698
                 ranges.push((start_letter, end_letter));
550
-                if !self.eat(&TokenKind::Comma) { break; }
699
+                if !self.eat(&TokenKind::Comma) {
700
+                    break;
701
+                }
551702
             }
552703
             self.expect(&TokenKind::RParen)?;
553704
             specs.push(ImplicitSpec { type_spec, ranges });
554
-            if !self.eat(&TokenKind::Comma) { break; }
705
+            if !self.eat(&TokenKind::Comma) {
706
+                break;
707
+            }
555708
         }
556709
 
557710
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
@@ -570,9 +723,18 @@ impl<'a> Parser<'a> {
570723
         while self.eat(&TokenKind::Comma) {
571724
             let text = self.peek_text().to_lowercase();
572725
             match text.as_str() {
573
-                "abstract" => { self.advance(); attrs.push(TypeAttr::Abstract); }
574
-                "public" => { self.advance(); attrs.push(TypeAttr::Public); }
575
-                "private" => { self.advance(); attrs.push(TypeAttr::Private); }
726
+                "abstract" => {
727
+                    self.advance();
728
+                    attrs.push(TypeAttr::Abstract);
729
+                }
730
+                "public" => {
731
+                    self.advance();
732
+                    attrs.push(TypeAttr::Public);
733
+                }
734
+                "private" => {
735
+                    self.advance();
736
+                    attrs.push(TypeAttr::Private);
737
+                }
576738
                 "bind" => {
577739
                     self.advance();
578740
                     let name = self.parse_bind_spec()?;
@@ -609,8 +771,12 @@ impl<'a> Parser<'a> {
609771
                 loop {
610772
                     self.skip_newlines();
611773
                     let proc_text = self.peek_text().to_lowercase();
612
-                    if proc_text == "end" { break; }
613
-                    if proc_text == "endtype" { break; }
774
+                    if proc_text == "end" {
775
+                        break;
776
+                    }
777
+                    if proc_text == "endtype" {
778
+                        break;
779
+                    }
614780
 
615781
                     if proc_text == "procedure" {
616782
                         self.advance();
@@ -627,7 +793,9 @@ impl<'a> Parser<'a> {
627793
                         final_procs.push(name);
628794
                     } else {
629795
                         // Skip unknown lines in contains section.
630
-                        while !self.at_stmt_end() { self.advance(); }
796
+                        while !self.at_stmt_end() {
797
+                            self.advance();
798
+                        }
631799
                     }
632800
                     self.skip_newlines();
633801
                 }
@@ -645,7 +813,9 @@ impl<'a> Parser<'a> {
645813
                 components.push(comp);
646814
             } else {
647815
                 // Skip unrecognized lines.
648
-                while !self.at_stmt_end() { self.advance(); }
816
+                while !self.at_stmt_end() {
817
+                    self.advance();
818
+                }
649819
                 self.skip_newlines();
650820
             }
651821
         }
@@ -663,13 +833,25 @@ impl<'a> Parser<'a> {
663833
         }
664834
 
665835
         let extends = attrs.iter().find_map(|a| {
666
-            if let TypeAttr::Extends(ref p) = a { Some(p.clone()) } else { None }
836
+            if let TypeAttr::Extends(ref p) = a {
837
+                Some(p.clone())
838
+            } else {
839
+                None
840
+            }
667841
         });
668842
 
669843
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
670
-        Ok(Spanned::new(Decl::DerivedTypeDef {
671
-            name, extends, attrs, components, type_bound_procs, final_procs,
672
-        }, span))
844
+        Ok(Spanned::new(
845
+            Decl::DerivedTypeDef {
846
+                name,
847
+                extends,
848
+                attrs,
849
+                components,
850
+                type_bound_procs,
851
+                final_procs,
852
+            },
853
+            span,
854
+        ))
673855
     }
674856
 
675857
     fn parse_type_bound_proc(&mut self) -> Result<TypeBoundProc, ParseError> {
@@ -691,7 +873,12 @@ impl<'a> Parser<'a> {
691873
         } else {
692874
             None
693875
         };
694
-        Ok(TypeBoundProc { name, binding, attrs: proc_attrs, is_generic: false })
876
+        Ok(TypeBoundProc {
877
+            name,
878
+            binding,
879
+            attrs: proc_attrs,
880
+            is_generic: false,
881
+        })
695882
     }
696883
 
697884
     fn parse_type_bound_proc_generic(&mut self) -> Result<TypeBoundProc, ParseError> {
@@ -711,7 +898,12 @@ impl<'a> Parser<'a> {
711898
         } else {
712899
             None
713900
         };
714
-        Ok(TypeBoundProc { name, binding, attrs: Vec::new(), is_generic: true })
901
+        Ok(TypeBoundProc {
902
+            name,
903
+            binding,
904
+            attrs: Vec::new(),
905
+            is_generic: true,
906
+        })
715907
     }
716908
 
717909
     // ---- PARAMETER, COMMON, EQUIVALENCE, DATA ----
@@ -726,7 +918,9 @@ impl<'a> Parser<'a> {
726918
             self.expect(&TokenKind::Assign)?;
727919
             let value = self.parse_expr()?;
728920
             pairs.push((name, value));
729
-            if !self.eat(&TokenKind::Comma) { break; }
921
+            if !self.eat(&TokenKind::Comma) {
922
+                break;
923
+            }
730924
         }
731925
         self.expect(&TokenKind::RParen)?;
732926
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
@@ -746,7 +940,9 @@ impl<'a> Parser<'a> {
746940
         let mut vars = Vec::new();
747941
         loop {
748942
             vars.push(self.advance().clone().text);
749
-            if !self.eat(&TokenKind::Comma) { break; }
943
+            if !self.eat(&TokenKind::Comma) {
944
+                break;
945
+            }
750946
         }
751947
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
752948
         Ok(Spanned::new(Decl::CommonBlock { name, vars }, span))
@@ -763,19 +959,27 @@ impl<'a> Parser<'a> {
763959
             let mut objects = Vec::new();
764960
             while self.peek() != &TokenKind::Slash {
765961
                 objects.push(self.parse_expr_bp(BP_MUL.right)?);
766
-                if !self.eat(&TokenKind::Comma) { break; }
962
+                if !self.eat(&TokenKind::Comma) {
963
+                    break;
964
+                }
767965
             }
768966
             self.expect(&TokenKind::Slash)?;
769967
             let mut values = Vec::new();
770968
             while self.peek() != &TokenKind::Slash {
771969
                 values.push(self.parse_expr_bp(BP_MUL.right)?);
772
-                if !self.eat(&TokenKind::Comma) { break; }
970
+                if !self.eat(&TokenKind::Comma) {
971
+                    break;
972
+                }
773973
             }
774974
             self.expect(&TokenKind::Slash)?;
775975
             sets.push(DataSet { objects, values });
776
-            if !self.eat(&TokenKind::Comma) { break; }
976
+            if !self.eat(&TokenKind::Comma) {
977
+                break;
978
+            }
777979
             // Check if next batch starts or if we're at end of statement.
778
-            if self.at_stmt_end() { break; }
980
+            if self.at_stmt_end() {
981
+                break;
982
+            }
779983
         }
780984
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
781985
         Ok(Spanned::new(Decl::DataStmt { sets }, span))
@@ -790,11 +994,15 @@ impl<'a> Parser<'a> {
790994
             let mut group = Vec::new();
791995
             loop {
792996
                 group.push(self.parse_expr()?);
793
-                if !self.eat(&TokenKind::Comma) { break; }
997
+                if !self.eat(&TokenKind::Comma) {
998
+                    break;
999
+                }
7941000
             }
7951001
             self.expect(&TokenKind::RParen)?;
7961002
             groups.push(group);
797
-            if !self.eat(&TokenKind::Comma) { break; }
1003
+            if !self.eat(&TokenKind::Comma) {
1004
+                break;
1005
+            }
7981006
         }
7991007
         let span = crate::parser::expr::span_from_to(start, self.prev_span());
8001008
         Ok(Spanned::new(Decl::EquivalenceStmt { groups }, span))
@@ -860,11 +1068,18 @@ mod tests {
8601068
     #[test]
8611069
     fn integer_simple() {
8621070
         let d = parse_decl("integer :: x, y, z");
863
-        if let Decl::TypeDecl { type_spec, entities, .. } = &d.node {
1071
+        if let Decl::TypeDecl {
1072
+            type_spec,
1073
+            entities,
1074
+            ..
1075
+        } = &d.node
1076
+        {
8641077
             assert!(matches!(type_spec, TypeSpec::Integer(None)));
8651078
             assert_eq!(entities.len(), 3);
8661079
             assert_eq!(entities[0].name, "x");
867
-        } else { panic!("not TypeDecl"); }
1080
+        } else {
1081
+            panic!("not TypeDecl");
1082
+        }
8681083
     }
8691084
 
8701085
     #[test]
@@ -873,7 +1088,9 @@ mod tests {
8731088
         if let Decl::TypeDecl { entities, .. } = &d.node {
8741089
             assert!(entities[0].init.is_some());
8751090
             assert!(entities[1].init.is_some());
876
-        } else { panic!("not TypeDecl"); }
1091
+        } else {
1092
+            panic!("not TypeDecl");
1093
+        }
8771094
     }
8781095
 
8791096
     #[test]
@@ -881,39 +1098,64 @@ mod tests {
8811098
         let d = parse_decl("integer(8) :: x");
8821099
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
8831100
             assert!(matches!(type_spec, TypeSpec::Integer(Some(_))));
884
-        } else { panic!("not TypeDecl"); }
1101
+        } else {
1102
+            panic!("not TypeDecl");
1103
+        }
8851104
     }
8861105
 
8871106
     #[test]
8881107
     fn real_allocatable() {
8891108
         let d = parse_decl("real(8), allocatable :: matrix(:,:)");
890
-        if let Decl::TypeDecl { type_spec, attrs, entities } = &d.node {
1109
+        if let Decl::TypeDecl {
1110
+            type_spec,
1111
+            attrs,
1112
+            entities,
1113
+        } = &d.node
1114
+        {
8911115
             assert!(matches!(type_spec, TypeSpec::Real(Some(_))));
8921116
             assert!(attrs.contains(&Attribute::Allocatable));
8931117
             assert!(entities[0].array_spec.is_some());
894
-        } else { panic!("not TypeDecl"); }
1118
+        } else {
1119
+            panic!("not TypeDecl");
1120
+        }
8951121
     }
8961122
 
8971123
     #[test]
8981124
     fn character_deferred_length() {
8991125
         let d = parse_decl("character(len=:), allocatable :: name");
900
-        if let Decl::TypeDecl { type_spec, attrs, .. } = &d.node {
1126
+        if let Decl::TypeDecl {
1127
+            type_spec, attrs, ..
1128
+        } = &d.node
1129
+        {
9011130
             if let TypeSpec::Character(Some(cs)) = type_spec {
9021131
                 assert!(matches!(cs.len, Some(LenSpec::Colon)));
903
-            } else { panic!("not character type"); }
1132
+            } else {
1133
+                panic!("not character type");
1134
+            }
9041135
             assert!(attrs.contains(&Attribute::Allocatable));
905
-        } else { panic!("not TypeDecl"); }
1136
+        } else {
1137
+            panic!("not TypeDecl");
1138
+        }
9061139
     }
9071140
 
9081141
     #[test]
9091142
     fn character_assumed_length() {
9101143
         let d = parse_decl("character(len=*), intent(in) :: input");
911
-        if let Decl::TypeDecl { type_spec, attrs, .. } = &d.node {
1144
+        if let Decl::TypeDecl {
1145
+            type_spec, attrs, ..
1146
+        } = &d.node
1147
+        {
9121148
             if let TypeSpec::Character(Some(cs)) = type_spec {
9131149
                 assert!(matches!(cs.len, Some(LenSpec::Star)));
914
-            } else { panic!("not character type"); }
915
-            assert!(attrs.iter().any(|a| matches!(a, Attribute::Intent(Intent::In))));
916
-        } else { panic!("not TypeDecl"); }
1150
+            } else {
1151
+                panic!("not character type");
1152
+            }
1153
+            assert!(attrs
1154
+                .iter()
1155
+                .any(|a| matches!(a, Attribute::Intent(Intent::In))));
1156
+        } else {
1157
+            panic!("not TypeDecl");
1158
+        }
9171159
     }
9181160
 
9191161
     #[test]
@@ -921,7 +1163,9 @@ mod tests {
9211163
         let d = parse_decl("type(my_type) :: obj");
9221164
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
9231165
             assert!(matches!(type_spec, TypeSpec::Type(ref n) if n == "my_type"));
924
-        } else { panic!("not TypeDecl"); }
1166
+        } else {
1167
+            panic!("not TypeDecl");
1168
+        }
9251169
     }
9261170
 
9271171
     #[test]
@@ -929,7 +1173,9 @@ mod tests {
9291173
         let d = parse_decl("class(*) :: poly");
9301174
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
9311175
             assert!(matches!(type_spec, TypeSpec::ClassStar));
932
-        } else { panic!("not TypeDecl"); }
1176
+        } else {
1177
+            panic!("not TypeDecl");
1178
+        }
9331179
     }
9341180
 
9351181
     #[test]
@@ -937,23 +1183,33 @@ mod tests {
9371183
         let d = parse_decl("type(node), pointer :: ptr => null()");
9381184
         if let Decl::TypeDecl { entities, .. } = &d.node {
9391185
             assert!(entities[0].ptr_init.is_some());
940
-        } else { panic!("not TypeDecl"); }
1186
+        } else {
1187
+            panic!("not TypeDecl");
1188
+        }
9411189
     }
9421190
 
9431191
     #[test]
9441192
     fn intent_inout() {
9451193
         let d = parse_decl("real, intent(inout) :: x");
9461194
         if let Decl::TypeDecl { attrs, .. } = &d.node {
947
-            assert!(attrs.iter().any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
948
-        } else { panic!("not TypeDecl"); }
1195
+            assert!(attrs
1196
+                .iter()
1197
+                .any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
1198
+        } else {
1199
+            panic!("not TypeDecl");
1200
+        }
9491201
     }
9501202
 
9511203
     #[test]
9521204
     fn intent_in_out_two_words() {
9531205
         let d = parse_decl("real, intent(in out) :: x");
9541206
         if let Decl::TypeDecl { attrs, .. } = &d.node {
955
-            assert!(attrs.iter().any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
956
-        } else { panic!("not TypeDecl"); }
1207
+            assert!(attrs
1208
+                .iter()
1209
+                .any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
1210
+        } else {
1211
+            panic!("not TypeDecl");
1212
+        }
9571213
     }
9581214
 
9591215
     #[test]
@@ -962,8 +1218,12 @@ mod tests {
9621218
         if let Decl::TypeDecl { attrs, .. } = &d.node {
9631219
             assert!(attrs.iter().any(|a| matches!(a, Attribute::Dimension(_))));
9641220
             assert!(attrs.contains(&Attribute::Allocatable));
965
-            assert!(attrs.iter().any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
966
-        } else { panic!("not TypeDecl"); }
1221
+            assert!(attrs
1222
+                .iter()
1223
+                .any(|a| matches!(a, Attribute::Intent(Intent::InOut))));
1224
+        } else {
1225
+            panic!("not TypeDecl");
1226
+        }
9671227
     }
9681228
 
9691229
     #[test]
@@ -972,7 +1232,9 @@ mod tests {
9721232
         if let Decl::TypeDecl { entities, .. } = &d.node {
9731233
             assert_eq!(entities.len(), 2);
9741234
             assert_eq!(entities[0].name, "x");
975
-        } else { panic!("not TypeDecl"); }
1235
+        } else {
1236
+            panic!("not TypeDecl");
1237
+        }
9761238
     }
9771239
 
9781240
     #[test]
@@ -980,7 +1242,9 @@ mod tests {
9801242
         let d = parse_decl("double precision :: x");
9811243
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
9821244
             assert!(matches!(type_spec, TypeSpec::DoublePrecision));
983
-        } else { panic!("not TypeDecl"); }
1245
+        } else {
1246
+            panic!("not TypeDecl");
1247
+        }
9841248
     }
9851249
 
9861250
     #[test]
@@ -988,7 +1252,9 @@ mod tests {
9881252
         let d = parse_decl("integer, bind(c) :: x");
9891253
         if let Decl::TypeDecl { attrs, .. } = &d.node {
9901254
             assert!(attrs.iter().any(|a| matches!(a, Attribute::Bind(None))));
991
-        } else { panic!("not TypeDecl"); }
1255
+        } else {
1256
+            panic!("not TypeDecl");
1257
+        }
9921258
     }
9931259
 
9941260
     // ---- USE statements ----
@@ -999,7 +1265,9 @@ mod tests {
9991265
         if let Decl::UseStmt { module, nature, .. } = &d.node {
10001266
             assert_eq!(module, "my_module");
10011267
             assert_eq!(*nature, UseNature::Normal);
1002
-        } else { panic!("not UseStmt"); }
1268
+        } else {
1269
+            panic!("not UseStmt");
1270
+        }
10031271
     }
10041272
 
10051273
     #[test]
@@ -1008,7 +1276,9 @@ mod tests {
10081276
         if let Decl::UseStmt { only, .. } = &d.node {
10091277
             let items = only.as_ref().unwrap();
10101278
             assert_eq!(items.len(), 2);
1011
-        } else { panic!("not UseStmt"); }
1279
+        } else {
1280
+            panic!("not UseStmt");
1281
+        }
10121282
     }
10131283
 
10141284
     #[test]
@@ -1017,7 +1287,9 @@ mod tests {
10171287
         if let Decl::UseStmt { module, nature, .. } = &d.node {
10181288
             assert_eq!(module, "iso_c_binding");
10191289
             assert_eq!(*nature, UseNature::Intrinsic);
1020
-        } else { panic!("not UseStmt"); }
1290
+        } else {
1291
+            panic!("not UseStmt");
1292
+        }
10211293
     }
10221294
 
10231295
     #[test]
@@ -1026,7 +1298,9 @@ mod tests {
10261298
         if let Decl::UseStmt { only, .. } = &d.node {
10271299
             let items = only.as_ref().unwrap();
10281300
             assert!(matches!(&items[0], OnlyItem::Rename(_)));
1029
-        } else { panic!("not UseStmt"); }
1301
+        } else {
1302
+            panic!("not UseStmt");
1303
+        }
10301304
     }
10311305
 
10321306
     // ---- IMPLICIT ----
@@ -1034,13 +1308,25 @@ mod tests {
10341308
     #[test]
10351309
     fn implicit_none() {
10361310
         let d = parse_decl("implicit none");
1037
-        assert!(matches!(d.node, Decl::ImplicitNone { type_: true, external: false }));
1311
+        assert!(matches!(
1312
+            d.node,
1313
+            Decl::ImplicitNone {
1314
+                type_: true,
1315
+                external: false
1316
+            }
1317
+        ));
10381318
     }
10391319
 
10401320
     #[test]
10411321
     fn implicit_none_type_external() {
10421322
         let d = parse_decl("implicit none(type, external)");
1043
-        assert!(matches!(d.node, Decl::ImplicitNone { type_: true, external: true }));
1323
+        assert!(matches!(
1324
+            d.node,
1325
+            Decl::ImplicitNone {
1326
+                type_: true,
1327
+                external: true
1328
+            }
1329
+        ));
10441330
     }
10451331
 
10461332
     #[test]
@@ -1050,7 +1336,9 @@ mod tests {
10501336
             assert_eq!(specs.len(), 1);
10511337
             assert!(matches!(specs[0].type_spec, TypeSpec::DoublePrecision));
10521338
             assert_eq!(specs[0].ranges.len(), 2);
1053
-        } else { panic!("not ImplicitStmt"); }
1339
+        } else {
1340
+            panic!("not ImplicitStmt");
1341
+        }
10541342
     }
10551343
 
10561344
     // ---- PARAMETER, COMMON, DATA, EQUIVALENCE ----
@@ -1062,7 +1350,9 @@ mod tests {
10621350
             assert_eq!(pairs.len(), 2);
10631351
             assert_eq!(pairs[0].0, "pi");
10641352
             assert_eq!(pairs[1].0, "e");
1065
-        } else { panic!("not ParameterStmt"); }
1353
+        } else {
1354
+            panic!("not ParameterStmt");
1355
+        }
10661356
     }
10671357
 
10681358
     #[test]
@@ -1071,7 +1361,9 @@ mod tests {
10711361
         if let Decl::CommonBlock { name, vars } = &d.node {
10721362
             assert_eq!(name.as_deref(), Some("block1"));
10731363
             assert_eq!(vars.len(), 3);
1074
-        } else { panic!("not CommonBlock"); }
1364
+        } else {
1365
+            panic!("not CommonBlock");
1366
+        }
10751367
     }
10761368
 
10771369
     #[test]
@@ -1079,7 +1371,9 @@ mod tests {
10791371
         let d = parse_decl("data x /1.0/, y /2.0/");
10801372
         if let Decl::DataStmt { sets } = &d.node {
10811373
             assert_eq!(sets.len(), 2);
1082
-        } else { panic!("not DataStmt"); }
1374
+        } else {
1375
+            panic!("not DataStmt");
1376
+        }
10831377
     }
10841378
 
10851379
     #[test]
@@ -1088,7 +1382,9 @@ mod tests {
10881382
         if let Decl::EquivalenceStmt { groups } = &d.node {
10891383
             assert_eq!(groups.len(), 2);
10901384
             assert_eq!(groups[0].len(), 2);
1091
-        } else { panic!("not EquivalenceStmt"); }
1385
+        } else {
1386
+            panic!("not EquivalenceStmt");
1387
+        }
10921388
     }
10931389
 
10941390
     // ---- Audit test gap coverage ----
@@ -1097,8 +1393,13 @@ mod tests {
10971393
     fn real_star8_old_style() {
10981394
         let d = parse_decl("real*8 :: x");
10991395
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
1100
-            assert!(matches!(type_spec, TypeSpec::Real(Some(KindSelector::Star(_)))));
1101
-        } else { panic!("not TypeDecl"); }
1396
+            assert!(matches!(
1397
+                type_spec,
1398
+                TypeSpec::Real(Some(KindSelector::Star(_)))
1399
+            ));
1400
+        } else {
1401
+            panic!("not TypeDecl");
1402
+        }
11021403
     }
11031404
 
11041405
     #[test]
@@ -1107,8 +1408,12 @@ mod tests {
11071408
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11081409
             if let TypeSpec::Character(Some(cs)) = type_spec {
11091410
                 assert!(matches!(cs.len, Some(LenSpec::Expr(_))));
1110
-            } else { panic!("not character type"); }
1111
-        } else { panic!("not TypeDecl"); }
1411
+            } else {
1412
+                panic!("not character type");
1413
+            }
1414
+        } else {
1415
+            panic!("not TypeDecl");
1416
+        }
11121417
     }
11131418
 
11141419
     #[test]
@@ -1116,7 +1421,9 @@ mod tests {
11161421
         let d = parse_decl("integer(kind=4) :: x");
11171422
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11181423
             assert!(matches!(type_spec, TypeSpec::Integer(Some(_))));
1119
-        } else { panic!("not TypeDecl"); }
1424
+        } else {
1425
+            panic!("not TypeDecl");
1426
+        }
11201427
     }
11211428
 
11221429
     #[test]
@@ -1124,7 +1431,9 @@ mod tests {
11241431
         let d = parse_decl("class(my_type) :: x");
11251432
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11261433
             assert!(matches!(type_spec, TypeSpec::Class(ref n) if n == "my_type"));
1127
-        } else { panic!("not TypeDecl"); }
1434
+        } else {
1435
+            panic!("not TypeDecl");
1436
+        }
11281437
     }
11291438
 
11301439
     #[test]
@@ -1132,7 +1441,9 @@ mod tests {
11321441
         let d = parse_decl("type(*) :: x");
11331442
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11341443
             assert!(matches!(type_spec, TypeSpec::TypeStar));
1135
-        } else { panic!("not TypeDecl"); }
1444
+        } else {
1445
+            panic!("not TypeDecl");
1446
+        }
11361447
     }
11371448
 
11381449
     #[test]
@@ -1169,7 +1480,9 @@ mod tests {
11691480
         let d = parse_decl("logical :: flag");
11701481
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11711482
             assert!(matches!(type_spec, TypeSpec::Logical(None)));
1172
-        } else { panic!("not TypeDecl"); }
1483
+        } else {
1484
+            panic!("not TypeDecl");
1485
+        }
11731486
     }
11741487
 
11751488
     #[test]
@@ -1177,7 +1490,9 @@ mod tests {
11771490
         let d = parse_decl("complex :: z");
11781491
         if let Decl::TypeDecl { type_spec, .. } = &d.node {
11791492
             assert!(matches!(type_spec, TypeSpec::Complex(None)));
1180
-        } else { panic!("not TypeDecl"); }
1493
+        } else {
1494
+            panic!("not TypeDecl");
1495
+        }
11811496
     }
11821497
 
11831498
     #[test]
@@ -1185,7 +1500,9 @@ mod tests {
11851500
         let d = parse_decl("implicit integer (i-n)");
11861501
         if let Decl::ImplicitStmt { specs } = &d.node {
11871502
             assert!(matches!(specs[0].type_spec, TypeSpec::Integer(_)));
1188
-        } else { panic!("not ImplicitStmt"); }
1503
+        } else {
1504
+            panic!("not ImplicitStmt");
1505
+        }
11891506
     }
11901507
 
11911508
     #[test]
@@ -1193,7 +1510,9 @@ mod tests {
11931510
         let d = parse_decl("use :: my_module");
11941511
         if let Decl::UseStmt { module, .. } = &d.node {
11951512
             assert_eq!(module, "my_module");
1196
-        } else { panic!("not UseStmt"); }
1513
+        } else {
1514
+            panic!("not UseStmt");
1515
+        }
11971516
     }
11981517
 
11991518
     #[test]
@@ -1201,7 +1520,9 @@ mod tests {
12011520
         let d = parse_decl("integer, bind(c, name='cfunc') :: x");
12021521
         if let Decl::TypeDecl { attrs, .. } = &d.node {
12031522
             assert!(attrs.iter().any(|a| matches!(a, Attribute::Bind(Some(_)))));
1204
-        } else { panic!("not TypeDecl"); }
1523
+        } else {
1524
+            panic!("not TypeDecl");
1525
+        }
12051526
     }
12061527
 
12071528
     #[test]
@@ -1209,7 +1530,9 @@ mod tests {
12091530
         let d = parse_decl("integer, save :: x");
12101531
         if let Decl::TypeDecl { attrs, .. } = &d.node {
12111532
             assert!(attrs.contains(&Attribute::Save));
1212
-        } else { panic!("not TypeDecl"); }
1533
+        } else {
1534
+            panic!("not TypeDecl");
1535
+        }
12131536
     }
12141537
 
12151538
     #[test]
@@ -1217,6 +1540,8 @@ mod tests {
12171540
         let d = parse_decl("integer, value :: x");
12181541
         if let Decl::TypeDecl { attrs, .. } = &d.node {
12191542
             assert!(attrs.contains(&Attribute::Value));
1220
-        } else { panic!("not TypeDecl"); }
1543
+        } else {
1544
+            panic!("not TypeDecl");
1545
+        }
12211546
     }
12221547
 }
src/parser/expr.rsmodified
557 lines changed — click to load
@@ -5,10 +5,10 @@
55
 //! unary operators, function calls, array constructors, and
66
 //! component access chains.
77
 
8
-use crate::ast::Spanned;
8
+use super::{ParseError, Parser};
99
 use crate::ast::expr::*;
10
-use crate::lexer::{TokenKind, Span};
11
-use super::{Parser, ParseError};
10
+use crate::ast::Spanned;
11
+use crate::lexer::{Span, TokenKind};
1212
 
1313
 /// Binding power for Pratt parsing.
1414
 /// Higher = tighter binding. Each level has left and right binding power.
@@ -24,18 +24,33 @@ pub(crate) struct Bp {
2424
 // Precedence levels (from Fortran standard, lowest to highest).
2525
 // We use even numbers for left bp, odd for right, to create the half-levels
2626
 // needed for associativity.
27
-const BP_DEFINED_BINARY: Bp = Bp { left: 2, right: 3 };  // .myop. (binary)
28
-const BP_EQV: Bp = Bp { left: 4, right: 5 };             // .eqv., .neqv.
29
-const BP_OR: Bp = Bp { left: 6, right: 7 };              // .or.
30
-const BP_AND: Bp = Bp { left: 8, right: 9 };             // .and.
31
-const BP_NOT: u8 = 10;                                    // .not. (unary, right)
32
-const BP_COMPARISON: Bp = Bp { left: 12, right: 12 };    // ==, /=, <, >, <=, >= (non-assoc)
33
-const BP_CONCAT: Bp = Bp { left: 14, right: 15 };        // //
34
-const BP_ADD: Bp = Bp { left: 16, right: 17 };           // +, - (binary)
35
-const BP_UNARY_ADD: u8 = 18;                              // +, - (unary)
36
-pub(crate) const BP_MUL: Bp = Bp { left: 20, right: 21 };           // *, /
37
-const BP_POW: Bp = Bp { left: 23, right: 22 };           // ** (RIGHT-assoc: left > right)
38
-const BP_DEFINED_UNARY: u8 = 24;                          // .myop. (unary)
27
+const BP_DEFINED_BINARY: Bp = Bp { left: 2, right: 3 }; // .myop. (binary)
28
+const BP_EQV: Bp = Bp { left: 4, right: 5 }; // .eqv., .neqv.
29
+const BP_OR: Bp = Bp { left: 6, right: 7 }; // .or.
30
+const BP_AND: Bp = Bp { left: 8, right: 9 }; // .and.
31
+const BP_NOT: u8 = 10; // .not. (unary, right)
32
+const BP_COMPARISON: Bp = Bp {
33
+    left: 12,
34
+    right: 12,
35
+}; // ==, /=, <, >, <=, >= (non-assoc)
36
+const BP_CONCAT: Bp = Bp {
37
+    left: 14,
38
+    right: 15,
39
+}; // //
40
+const BP_ADD: Bp = Bp {
41
+    left: 16,
42
+    right: 17,
43
+}; // +, - (binary)
44
+const BP_UNARY_ADD: u8 = 18; // +, - (unary)
45
+pub(crate) const BP_MUL: Bp = Bp {
46
+    left: 20,
47
+    right: 21,
48
+}; // *, /
49
+const BP_POW: Bp = Bp {
50
+    left: 23,
51
+    right: 22,
52
+}; // ** (RIGHT-assoc: left > right)
53
+const BP_DEFINED_UNARY: u8 = 24; // .myop. (unary)
3954
 
4055
 impl<'a> Parser<'a> {
4156
     /// Parse an expression.
@@ -55,13 +70,16 @@ impl<'a> Parser<'a> {
5570
 
5671
             // Check for infix operator.
5772
             let Some(bp) = self.infix_bp() else { break };
58
-            if bp.left < min_bp { break; }
73
+            if bp.left < min_bp {
74
+                break;
75
+            }
5976
 
6077
             // Non-associative operators: if left_bp == right_bp and we're at the
6178
             // same precedence level, reject chaining (e.g., a < b < c is illegal).
6279
             if bp.left == bp.right && bp.left == min_bp {
6380
                 return Err(self.error(
64
-                    "chained comparison operators are not allowed in Fortran (non-associative)".into()
81
+                    "chained comparison operators are not allowed in Fortran (non-associative)"
82
+                        .into(),
6583
                 ));
6684
             }
6785
 
@@ -75,11 +93,14 @@ impl<'a> Parser<'a> {
7593
                 end: right.span.end,
7694
             };
7795
 
78
-            left = Spanned::new(Expr::BinaryOp {
79
-                op,
80
-                left: Box::new(left),
81
-                right: Box::new(right),
82
-            }, span);
96
+            left = Spanned::new(
97
+                Expr::BinaryOp {
98
+                    op,
99
+                    left: Box::new(left),
100
+                    right: Box::new(right),
101
+                },
102
+                span,
103
+            );
83104
         }
84105
 
85106
         Ok(left)
@@ -95,38 +116,50 @@ impl<'a> Parser<'a> {
95116
                 self.advance();
96117
                 let operand = self.parse_expr_bp(BP_UNARY_ADD)?;
97118
                 let span = span_from_to(start, operand.span);
98
-                Ok(Spanned::new(Expr::UnaryOp {
99
-                    op: UnaryOp::Plus,
100
-                    operand: Box::new(operand),
101
-                }, span))
119
+                Ok(Spanned::new(
120
+                    Expr::UnaryOp {
121
+                        op: UnaryOp::Plus,
122
+                        operand: Box::new(operand),
123
+                    },
124
+                    span,
125
+                ))
102126
             }
103127
             TokenKind::Minus => {
104128
                 self.advance();
105129
                 let operand = self.parse_expr_bp(BP_UNARY_ADD)?;
106130
                 let span = span_from_to(start, operand.span);
107
-                Ok(Spanned::new(Expr::UnaryOp {
108
-                    op: UnaryOp::Minus,
109
-                    operand: Box::new(operand),
110
-                }, span))
131
+                Ok(Spanned::new(
132
+                    Expr::UnaryOp {
133
+                        op: UnaryOp::Minus,
134
+                        operand: Box::new(operand),
135
+                    },
136
+                    span,
137
+                ))
111138
             }
112139
             TokenKind::DotOp(ref name) if name == "not" => {
113140
                 self.advance();
114141
                 let operand = self.parse_expr_bp(BP_NOT)?;
115142
                 let span = span_from_to(start, operand.span);
116
-                Ok(Spanned::new(Expr::UnaryOp {
117
-                    op: UnaryOp::Not,
118
-                    operand: Box::new(operand),
119
-                }, span))
143
+                Ok(Spanned::new(
144
+                    Expr::UnaryOp {
145
+                        op: UnaryOp::Not,
146
+                        operand: Box::new(operand),
147
+                    },
148
+                    span,
149
+                ))
120150
             }
121151
             TokenKind::DefinedOp(ref name) => {
122152
                 let op_name = name.clone();
123153
                 self.advance();
124154
                 let operand = self.parse_expr_bp(BP_DEFINED_UNARY)?;
125155
                 let span = span_from_to(start, operand.span);
126
-                Ok(Spanned::new(Expr::UnaryOp {
127
-                    op: UnaryOp::Defined(op_name),
128
-                    operand: Box::new(operand),
129
-                }, span))
156
+                Ok(Spanned::new(
157
+                    Expr::UnaryOp {
158
+                        op: UnaryOp::Defined(op_name),
159
+                        operand: Box::new(operand),
160
+                    },
161
+                    span,
162
+                ))
130163
             }
131164
 
132165
             // Parenthesized expression or array constructor (/ ... /).
@@ -142,16 +175,22 @@ impl<'a> Parser<'a> {
142175
                     let imag = self.parse_expr()?;
143176
                     self.expect(&TokenKind::RParen)?;
144177
                     let span = span_from_to(start, self.prev_span());
145
-                    return Ok(Spanned::new(Expr::ComplexLiteral {
146
-                        real: Box::new(inner),
147
-                        imag: Box::new(imag),
148
-                    }, span));
178
+                    return Ok(Spanned::new(
179
+                        Expr::ComplexLiteral {
180
+                            real: Box::new(inner),
181
+                            imag: Box::new(imag),
182
+                        },
183
+                        span,
184
+                    ));
149185
                 }
150186
                 self.expect(&TokenKind::RParen)?;
151187
                 let span = span_from_to(start, self.prev_span());
152
-                Ok(Spanned::new(Expr::ParenExpr {
153
-                    inner: Box::new(inner),
154
-                }, span))
188
+                Ok(Spanned::new(
189
+                    Expr::ParenExpr {
190
+                        inner: Box::new(inner),
191
+                    },
192
+                    span,
193
+                ))
155194
             }
156195
 
157196
             // Array constructor [...]
@@ -184,10 +223,13 @@ impl<'a> Parser<'a> {
184223
                     let args = self.parse_argument_list()?;
185224
                     self.expect(&TokenKind::RParen)?;
186225
                     let span = span_from_to(expr.span, self.prev_span());
187
-                    expr = Spanned::new(Expr::FunctionCall {
188
-                        callee: Box::new(expr),
189
-                        args,
190
-                    }, span);
226
+                    expr = Spanned::new(
227
+                        Expr::FunctionCall {
228
+                            callee: Box::new(expr),
229
+                            args,
230
+                        },
231
+                        span,
232
+                    );
191233
                 }
192234
                 // Component access: expr%name
193235
                 TokenKind::Percent => {
@@ -200,10 +242,13 @@ impl<'a> Parser<'a> {
200242
                         });
201243
                     }
202244
                     let span = span_from_to(expr.span, name_tok.span);
203
-                    expr = Spanned::new(Expr::ComponentAccess {
204
-                        base: Box::new(expr),
205
-                        component: name_tok.text,
206
-                    }, span);
245
+                    expr = Spanned::new(
246
+                        Expr::ComponentAccess {
247
+                            base: Box::new(expr),
248
+                            component: name_tok.text,
249
+                        },
250
+                        span,
251
+                    );
207252
                 }
208253
                 _ => break,
209254
             }
@@ -220,8 +265,12 @@ impl<'a> Parser<'a> {
220265
             TokenKind::Plus => Some(BP_ADD),
221266
             TokenKind::Minus => Some(BP_ADD),
222267
             TokenKind::Concat => Some(BP_CONCAT),
223
-            TokenKind::Eq | TokenKind::Ne | TokenKind::Lt |
224
-            TokenKind::Le | TokenKind::Gt | TokenKind::Ge => Some(BP_COMPARISON),
268
+            TokenKind::Eq
269
+            | TokenKind::Ne
270
+            | TokenKind::Lt
271
+            | TokenKind::Le
272
+            | TokenKind::Gt
273
+            | TokenKind::Ge => Some(BP_COMPARISON),
225274
             TokenKind::DotOp(ref name) => match name.as_str() {
226275
                 "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Some(BP_COMPARISON),
227276
                 "and" => Some(BP_AND),
@@ -253,20 +302,25 @@ impl<'a> Parser<'a> {
253302
         let tok = self.advance().clone();
254303
         // Strip outer quotes for the value.
255304
         let value = if tok.text.len() >= 2 {
256
-            tok.text[1..tok.text.len()-1].replace("''", "'").replace("\"\"", "\"")
305
+            tok.text[1..tok.text.len() - 1]
306
+                .replace("''", "'")
307
+                .replace("\"\"", "\"")
257308
         } else {
258309
             tok.text.clone()
259310
         };
260
-        Ok(Spanned::new(Expr::StringLiteral { value, kind: None }, tok.span))
311
+        Ok(Spanned::new(
312
+            Expr::StringLiteral { value, kind: None },
313
+            tok.span,
314
+        ))
261315
     }
262316
 
263317
     fn parse_logical_literal(&mut self) -> Result<SpannedExpr, ParseError> {
264318
         let tok = self.advance().clone();
265319
         let lower = tok.text.to_lowercase();
266320
         let value = lower.contains("true");
267
-        let kind = lower.find("._").map(|pos| {
268
-            lower[pos+2..].trim_end_matches('.').to_string()
269
-        });
321
+        let kind = lower
322
+            .find("._")
323
+            .map(|pos| lower[pos + 2..].trim_end_matches('.').to_string());
270324
         Ok(Spanned::new(Expr::LogicalLiteral { value, kind }, tok.span))
271325
     }
272326
 
@@ -278,7 +332,13 @@ impl<'a> Parser<'a> {
278332
             b'Z' | b'z' => BozBase::Hex,
279333
             _ => BozBase::Hex,
280334
         };
281
-        Ok(Spanned::new(Expr::BozLiteral { text: tok.text, base }, tok.span))
335
+        Ok(Spanned::new(
336
+            Expr::BozLiteral {
337
+                text: tok.text,
338
+                base,
339
+            },
340
+            tok.span,
341
+        ))
282342
     }
283343
 
284344
     fn parse_name(&mut self) -> Result<SpannedExpr, ParseError> {
@@ -297,7 +357,9 @@ impl<'a> Parser<'a> {
297357
         loop {
298358
             let arg = self.parse_argument()?;
299359
             args.push(arg);
300
-            if !self.eat(&TokenKind::Comma) { break; }
360
+            if !self.eat(&TokenKind::Comma) {
361
+                break;
362
+            }
301363
         }
302364
         Ok(args)
303365
     }
@@ -320,7 +382,10 @@ impl<'a> Parser<'a> {
320382
         // Leading colon → range with no start: :end or : or ::stride
321383
         if matches!(self.peek(), TokenKind::Colon | TokenKind::ColonColon) {
322384
             let sub = self.parse_range(None)?;
323
-            return Ok(Argument { keyword: None, value: sub });
385
+            return Ok(Argument {
386
+                keyword: None,
387
+                value: sub,
388
+            });
324389
         }
325390
 
326391
         // Parse an expression.
@@ -329,11 +394,17 @@ impl<'a> Parser<'a> {
329394
         // If followed by colon, it's a range: start:end[:stride]
330395
         if self.peek() == &TokenKind::Colon {
331396
             let sub = self.parse_range(Some(expr))?;
332
-            return Ok(Argument { keyword: None, value: sub });
397
+            return Ok(Argument {
398
+                keyword: None,
399
+                value: sub,
400
+            });
333401
         }
334402
 
335403
         // Plain element.
336
-        Ok(Argument { keyword: None, value: SectionSubscript::Element(expr) })
404
+        Ok(Argument {
405
+            keyword: None,
406
+            value: SectionSubscript::Element(expr),
407
+        })
337408
     }
338409
 
339410
     /// Parse a range subscript: [start]:end[:stride] or [start]: or :
@@ -341,23 +412,32 @@ impl<'a> Parser<'a> {
341412
     fn parse_range(&mut self, start: Option<SpannedExpr>) -> Result<SectionSubscript, ParseError> {
342413
         // Handle :: (ColonColon token) as two colons — means start::stride with no end.
343414
         if self.eat(&TokenKind::ColonColon) {
344
-            let stride = if !matches!(self.peek(),
345
-                TokenKind::Comma | TokenKind::RParen | TokenKind::RBracket)
346
-            {
415
+            let stride = if !matches!(
416
+                self.peek(),
417
+                TokenKind::Comma | TokenKind::RParen | TokenKind::RBracket
418
+            ) {
347419
                 Some(self.parse_expr()?)
348420
             } else {
349421
                 None
350422
             };
351
-            return Ok(SectionSubscript::Range { start, end: None, stride });
423
+            return Ok(SectionSubscript::Range {
424
+                start,
425
+                end: None,
426
+                stride,
427
+            });
352428
         }
353429
 
354430
         self.expect(&TokenKind::Colon)?; // consume first colon
355431
 
356432
         // Parse end (optional — absent if next is colon, comma, ), ], or ::).
357
-        let end = if !matches!(self.peek(),
358
-            TokenKind::Colon | TokenKind::ColonColon | TokenKind::Comma |
359
-            TokenKind::RParen | TokenKind::RBracket)
360
-        {
433
+        let end = if !matches!(
434
+            self.peek(),
435
+            TokenKind::Colon
436
+                | TokenKind::ColonColon
437
+                | TokenKind::Comma
438
+                | TokenKind::RParen
439
+                | TokenKind::RBracket
440
+        ) {
361441
             Some(self.parse_expr()?)
362442
         } else {
363443
             None
@@ -365,9 +445,10 @@ impl<'a> Parser<'a> {
365445
 
366446
         // Parse stride (optional, after second colon).
367447
         let stride = if self.eat(&TokenKind::Colon) {
368
-            if !matches!(self.peek(),
369
-                TokenKind::Comma | TokenKind::RParen | TokenKind::RBracket)
370
-            {
448
+            if !matches!(
449
+                self.peek(),
450
+                TokenKind::Comma | TokenKind::RParen | TokenKind::RBracket
451
+            ) {
371452
                 Some(self.parse_expr()?)
372453
             } else {
373454
                 None
@@ -389,12 +470,17 @@ impl<'a> Parser<'a> {
389470
         if self.peek() != &TokenKind::RBracket {
390471
             loop {
391472
                 values.push(self.parse_ac_value()?);
392
-                if !self.eat(&TokenKind::Comma) { break; }
473
+                if !self.eat(&TokenKind::Comma) {
474
+                    break;
475
+                }
393476
             }
394477
         }
395478
         self.expect(&TokenKind::RBracket)?;
396479
         let span = span_from_to(start, self.prev_span());
397
-        Ok(Spanned::new(Expr::ArrayConstructor { type_spec, values }, span))
480
+        Ok(Spanned::new(
481
+            Expr::ArrayConstructor { type_spec, values },
482
+            span,
483
+        ))
398484
     }
399485
 
400486
     fn parse_array_constructor_slash(&mut self, start: Span) -> Result<SpannedExpr, ParseError> {
@@ -409,14 +495,24 @@ impl<'a> Parser<'a> {
409495
         // parenthesised implied-do form and errored on `=`.
410496
         let mut values = Vec::new();
411497
         loop {
412
-            if matches!(self.peek(), TokenKind::Slash) { break; }
498
+            if matches!(self.peek(), TokenKind::Slash) {
499
+                break;
500
+            }
413501
             values.push(self.parse_ac_value_bracketed(BP_MUL.right)?);
414
-            if !self.eat(&TokenKind::Comma) { break; }
502
+            if !self.eat(&TokenKind::Comma) {
503
+                break;
504
+            }
415505
         }
416506
         self.expect(&TokenKind::Slash)?;
417507
         self.expect(&TokenKind::RParen)?;
418508
         let span = span_from_to(start, self.prev_span());
419
-        Ok(Spanned::new(Expr::ArrayConstructor { type_spec: None, values }, span))
509
+        Ok(Spanned::new(
510
+            Expr::ArrayConstructor {
511
+                type_spec: None,
512
+                values,
513
+            },
514
+            span,
515
+        ))
420516
     }
421517
 
422518
     /// Variant of parse_ac_value that honours a minimum binding
@@ -534,17 +630,23 @@ fn token_to_binary_op(tok: &crate::lexer::Token) -> Result<BinaryOp, ParseError>
534630
             "or" => Ok(BinaryOp::Or),
535631
             "eqv" => Ok(BinaryOp::Eqv),
536632
             "neqv" => Ok(BinaryOp::Neqv),
537
-            _ => Err(ParseError { span: tok.span, msg: format!("unknown dot-operator .{}.", name) }),
633
+            _ => Err(ParseError {
634
+                span: tok.span,
635
+                msg: format!("unknown dot-operator .{}.", name),
636
+            }),
538637
         },
539638
         TokenKind::DefinedOp(name) => Ok(BinaryOp::Defined(name.clone())),
540
-        _ => Err(ParseError { span: tok.span, msg: format!("expected operator, got {}", tok.kind) }),
639
+        _ => Err(ParseError {
640
+            span: tok.span,
641
+            msg: format!("expected operator, got {}", tok.kind),
642
+        }),
541643
     }
542644
 }
543645
 
544646
 fn split_kind_suffix(text: &str) -> (String, Option<String>) {
545647
     if let Some(pos) = text.find('_') {
546648
         let num = text[..pos].to_string();
547
-        let kind = text[pos+1..].to_string();
649
+        let kind = text[pos + 1..].to_string();
548650
         if kind.is_empty() {
549651
             (text.to_string(), None)
550652
         } else {
@@ -580,19 +682,58 @@ mod tests {
580682
 
581683
     // ---- Literals ----
582684
 
583
-    #[test] fn integer() { assert_eq!(sexpr("42"), "42"); }
584
-    #[test] fn integer_kind() { assert_eq!(sexpr("42_8"), "42"); }
585
-    #[test] fn real() { assert_eq!(sexpr("3.14"), "3.14"); }
586
-    #[test] fn real_exp() { assert_eq!(sexpr("1.0e5"), "1.0e5"); }
587
-    #[test] fn real_double() { assert_eq!(sexpr("1.0d0"), "1.0d0"); }
588
-    #[test] fn string_single() { assert_eq!(sexpr("'hello'"), "'hello'"); }
589
-    #[test] fn string_double() { assert_eq!(sexpr("\"hello\""), "'hello'"); }
590
-    #[test] fn logical_true() { assert_eq!(sexpr(".true."), ".true."); }
591
-    #[test] fn logical_false() { assert_eq!(sexpr(".false."), ".false."); }
592
-    #[test] fn boz() { assert_eq!(sexpr("B'1010'"), "B'1010'"); }
593
-    #[test] fn complex_literal() { assert_eq!(sexpr("(1.0, 2.0)"), "(1.0, 2.0)"); }
594
-    #[test] fn complex_literal_exprs() { assert_eq!(sexpr("(a + b, c * d)"), "((a + b), (c * d))"); }
595
-    #[test] fn name() { assert_eq!(sexpr("x"), "x"); }
685
+    #[test]
686
+    fn integer() {
687
+        assert_eq!(sexpr("42"), "42");
688
+    }
689
+    #[test]
690
+    fn integer_kind() {
691
+        assert_eq!(sexpr("42_8"), "42");
692
+    }
693
+    #[test]
694
+    fn real() {
695
+        assert_eq!(sexpr("3.14"), "3.14");
696
+    }
697
+    #[test]
698
+    fn real_exp() {
699
+        assert_eq!(sexpr("1.0e5"), "1.0e5");
700
+    }
701
+    #[test]
702
+    fn real_double() {
703
+        assert_eq!(sexpr("1.0d0"), "1.0d0");
704
+    }
705
+    #[test]
706
+    fn string_single() {
707
+        assert_eq!(sexpr("'hello'"), "'hello'");
708
+    }
709
+    #[test]
710
+    fn string_double() {
711
+        assert_eq!(sexpr("\"hello\""), "'hello'");
712
+    }
713
+    #[test]
714
+    fn logical_true() {
715
+        assert_eq!(sexpr(".true."), ".true.");
716
+    }
717
+    #[test]
718
+    fn logical_false() {
719
+        assert_eq!(sexpr(".false."), ".false.");
720
+    }
721
+    #[test]
722
+    fn boz() {
723
+        assert_eq!(sexpr("B'1010'"), "B'1010'");
724
+    }
725
+    #[test]
726
+    fn complex_literal() {
727
+        assert_eq!(sexpr("(1.0, 2.0)"), "(1.0, 2.0)");
728
+    }
729
+    #[test]
730
+    fn complex_literal_exprs() {
731
+        assert_eq!(sexpr("(a + b, c * d)"), "((a + b), (c * d))");
732
+    }
733
+    #[test]
734
+    fn name() {
735
+        assert_eq!(sexpr("x"), "x");
736
+    }
596737
 
597738
     // ---- Arithmetic precedence ----
598739
 
@@ -813,10 +954,7 @@ mod tests {
813954
 
814955
     #[test]
815956
     fn mixed_comparison_and_logical() {
816
-        assert_eq!(
817
-            sexpr("x > 0 .and. y < 10"),
818
-            "((x > 0) .and. (y < 10))"
819
-        );
957
+        assert_eq!(sexpr("x > 0 .and. y < 10"), "((x > 0) .and. (y < 10))");
820958
     }
821959
 
822960
     #[test]
@@ -878,12 +1016,24 @@ mod tests {
8781016
     }
8791017
 
8801018
     // ---- BOZ variants ----
881
-    #[test] fn boz_octal() { assert_eq!(sexpr("O'777'"), "O'777'"); }
882
-    #[test] fn boz_hex() { assert_eq!(sexpr("Z'FF'"), "Z'FF'"); }
1019
+    #[test]
1020
+    fn boz_octal() {
1021
+        assert_eq!(sexpr("O'777'"), "O'777'");
1022
+    }
1023
+    #[test]
1024
+    fn boz_hex() {
1025
+        assert_eq!(sexpr("Z'FF'"), "Z'FF'");
1026
+    }
8831027
 
8841028
     // ---- Real literal edge cases ----
885
-    #[test] fn real_leading_dot() { assert_eq!(sexpr(".5"), ".5"); }
886
-    #[test] fn real_trailing_dot() { assert_eq!(sexpr("5."), "5."); }
1029
+    #[test]
1030
+    fn real_leading_dot() {
1031
+        assert_eq!(sexpr(".5"), ".5");
1032
+    }
1033
+    #[test]
1034
+    fn real_trailing_dot() {
1035
+        assert_eq!(sexpr("5."), "5.");
1036
+    }
8871037
 
8881038
     // ---- Mixed postfix chains ----
8891039
     #[test]
src/parser/mod.rsmodified
61 lines changed — click to load
@@ -4,12 +4,12 @@
44
 //! Expression parsing uses a Pratt parser with 12 precedence levels
55
 //! matching the Fortran standard exactly.
66
 
7
-pub mod expr;
87
 pub mod decl;
8
+pub mod expr;
99
 pub mod stmt;
1010
 pub mod unit;
1111
 
12
-use crate::lexer::{Token, TokenKind, Span};
12
+use crate::lexer::{Span, Token, TokenKind};
1313
 
1414
 use std::fmt;
1515
 
@@ -22,7 +22,11 @@ pub struct ParseError {
2222
 
2323
 impl fmt::Display for ParseError {
2424
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25
-        write!(f, "{}:{}: error: {}", self.span.start.line, self.span.start.col, self.msg)
25
+        write!(
26
+            f,
27
+            "{}:{}: error: {}",
28
+            self.span.start.line, self.span.start.col, self.msg
29
+        )
2630
     }
2731
 }
2832
 
@@ -111,7 +115,10 @@ impl<'a> Parser<'a> {
111115
     /// F2018 §6.3.2: a semicolon separates statements on the same line
112116
     /// and is semantically equivalent to a newline.
113117
     pub fn skip_newlines(&mut self) {
114
-        while matches!(self.peek(), TokenKind::Newline | TokenKind::Comment | TokenKind::Semicolon) {
118
+        while matches!(
119
+            self.peek(),
120
+            TokenKind::Newline | TokenKind::Comment | TokenKind::Semicolon
121
+        ) {
115122
             self.advance();
116123
         }
117124
     }
@@ -140,13 +147,21 @@ impl<'a> Parser<'a> {
140147
 
141148
     /// Check if we're at a statement-ending token.
142149
     pub fn at_stmt_end(&self) -> bool {
143
-        matches!(self.peek(), TokenKind::Newline | TokenKind::Semicolon | TokenKind::Eof | TokenKind::Comment)
150
+        matches!(
151
+            self.peek(),
152
+            TokenKind::Newline | TokenKind::Semicolon | TokenKind::Eof | TokenKind::Comment
153
+        )
144154
     }
145155
 
146156
     /// Check if the token at offset `n` from current position is a statement terminator.
147157
     pub fn at_stmt_end_after(&self, n: usize) -> bool {
148158
         let idx = self.pos + n;
149
-        if idx >= self.tokens.len() { return true; }
150
-        matches!(self.tokens[idx].kind, TokenKind::Newline | TokenKind::Semicolon | TokenKind::Eof | TokenKind::Comment)
159
+        if idx >= self.tokens.len() {
160
+            return true;
161
+        }
162
+        matches!(
163
+            self.tokens[idx].kind,
164
+            TokenKind::Newline | TokenKind::Semicolon | TokenKind::Eof | TokenKind::Comment
165
+        )
151166
     }
152167
 }
src/parser/stmt.rsmodified
43 lines changed — click to load
@@ -99,7 +99,8 @@ impl<'a> Parser<'a> {
9999
                     Some(TokenKind::Identifier)
100100
                 );
101101
                 if looks_like_entry_stmt {
102
-                    Err(self.error("ENTRY statements are recognized but not yet implemented".into()))
102
+                    Err(self
103
+                        .error("ENTRY statements are recognized but not yet implemented".into()))
103104
                 } else {
104105
                     self.parse_assignment_or_call(start)
105106
                 }
@@ -178,7 +179,10 @@ impl<'a> Parser<'a> {
178179
                 let span = span_from_to(start, self.prev_span());
179180
                 Ok(Spanned::new(Stmt::Continue { label: None }, span))
180181
             }
181
-            "sync" => Err(self.error("coarray SYNC statements are recognized but not yet implemented".into())),
182
+            "sync" => {
183
+                Err(self
184
+                    .error("coarray SYNC statements are recognized but not yet implemented".into()))
185
+            }
182186
             _ => self.parse_assignment_or_call(start),
183187
         }
184188
     }
@@ -1179,9 +1183,10 @@ impl<'a> Parser<'a> {
11791183
         loop {
11801184
             self.skip_newlines();
11811185
             if self.peek() == &TokenKind::Eof {
1182
-                return Err(
1183
-                    self.error(format!("expected statement with terminating label {}", label))
1184
-                );
1186
+                return Err(self.error(format!(
1187
+                    "expected statement with terminating label {}",
1188
+                    label
1189
+                )));
11851190
             }
11861191
 
11871192
             let is_terminator = self.peek() == &TokenKind::IntegerLiteral
@@ -2310,7 +2315,9 @@ end if
23102315
         let tokens = Lexer::tokenize("entry g(y)\n", 0).unwrap();
23112316
         let mut parser = Parser::new(&tokens);
23122317
         let err = parser.parse_stmt().expect_err("ENTRY should not parse yet");
2313
-        assert!(err.msg.contains("ENTRY statements are recognized but not yet implemented"));
2318
+        assert!(err
2319
+            .msg
2320
+            .contains("ENTRY statements are recognized but not yet implemented"));
23142321
     }
23152322
 
23162323
     #[test]
src/preprocess/mod.rsmodified
697 lines changed — click to load
@@ -60,11 +60,21 @@ pub struct MacroDef {
6060
 
6161
 impl MacroDef {
6262
     pub fn object(body: &str) -> Self {
63
-        Self { body: body.into(), params: Vec::new(), is_function: false, is_variadic: false }
63
+        Self {
64
+            body: body.into(),
65
+            params: Vec::new(),
66
+            is_function: false,
67
+            is_variadic: false,
68
+        }
6469
     }
6570
 
6671
     pub fn function(params: Vec<String>, body: &str) -> Self {
67
-        Self { body: body.into(), params, is_function: true, is_variadic: false }
72
+        Self {
73
+            body: body.into(),
74
+            params,
75
+            is_function: true,
76
+            is_variadic: false,
77
+        }
6878
     }
6979
 }
7080
 
@@ -155,10 +165,20 @@ impl Preprocessor {
155165
 
156166
     fn make_source_loc(&self, filename: &str, line: u32) -> SourceLoc {
157167
         if let Some((override_line, ref override_file)) = self.line_override {
158
-            let fname = if override_file.is_empty() { filename } else { override_file.as_str() };
159
-            SourceLoc { filename: fname.into(), line: override_line }
168
+            let fname = if override_file.is_empty() {
169
+                filename
170
+            } else {
171
+                override_file.as_str()
172
+            };
173
+            SourceLoc {
174
+                filename: fname.into(),
175
+                line: override_line,
176
+            }
160177
         } else {
161
-            SourceLoc { filename: filename.into(), line }
178
+            SourceLoc {
179
+                filename: filename.into(),
180
+                line,
181
+            }
162182
         }
163183
     }
164184
 
@@ -176,11 +196,17 @@ impl Preprocessor {
176196
             return Err(PreprocError {
177197
                 filename: filename.into(),
178198
                 line: source.lines().count() as u32,
179
-                msg: format!("unterminated #if/#ifdef ({} level(s) still open)", self.cond_stack.len()),
199
+                msg: format!(
200
+                    "unterminated #if/#ifdef ({} level(s) still open)",
201
+                    self.cond_stack.len()
202
+                ),
180203
             });
181204
         }
182205
 
183
-        Ok(PreprocOutput { text: output, source_map })
206
+        Ok(PreprocOutput {
207
+            text: output,
208
+            source_map,
209
+        })
184210
     }
185211
 
186212
     fn process_into(
@@ -191,11 +217,20 @@ impl Preprocessor {
191217
         source_map: &mut Vec<SourceLoc>,
192218
     ) -> Result<(), PreprocError> {
193219
         // Set dynamic macros.
194
-        self.defines.insert("__FILE__".into(), MacroDef::object(&format!("\"{}\"", filename)));
220
+        self.defines.insert(
221
+            "__FILE__".into(),
222
+            MacroDef::object(&format!("\"{}\"", filename)),
223
+        );
195224
 
196225
         let now = current_datetime();
197
-        self.defines.insert("__DATE__".into(), MacroDef::object(&format!("\"{}\"", now.0)));
198
-        self.defines.insert("__TIME__".into(), MacroDef::object(&format!("\"{}\"", now.1)));
226
+        self.defines.insert(
227
+            "__DATE__".into(),
228
+            MacroDef::object(&format!("\"{}\"", now.0)),
229
+        );
230
+        self.defines.insert(
231
+            "__TIME__".into(),
232
+            MacroDef::object(&format!("\"{}\"", now.1)),
233
+        );
199234
 
200235
         // Process lines with inline backslash continuation joining,
201236
         // tracking original line numbers so __LINE__ and source_map are correct.
@@ -238,7 +273,10 @@ impl Preprocessor {
238273
             }
239274
 
240275
             // Update __LINE__ to the original starting line of this logical line.
241
-            self.defines.insert("__LINE__".into(), MacroDef::object(&orig_line_num.to_string()));
276
+            self.defines.insert(
277
+                "__LINE__".into(),
278
+                MacroDef::object(&orig_line_num.to_string()),
279
+            );
242280
 
243281
             // Fixed-form: C, c, or * in column 1 is a comment line.
244282
             if self.fixed_form {
@@ -307,7 +345,8 @@ impl Preprocessor {
307345
             "undef" => self.do_undef(args),
308346
             "include" => self.do_include(args, filename, line_num, output, source_map),
309347
             "error" => Err(PreprocError {
310
-                filename: filename.into(), line: line_num,
348
+                filename: filename.into(),
349
+                line: line_num,
311350
                 msg: format!("#error {}", args),
312351
             }),
313352
             "warning" => {
@@ -316,14 +355,16 @@ impl Preprocessor {
316355
             }
317356
             "line" => self.do_line(args, filename, line_num),
318357
             "" => Ok(()), // bare # is allowed (null directive)
319
-            _ => Ok(()), // unknown directives are ignored (like #pragma)
358
+            _ => Ok(()),  // unknown directives are ignored (like #pragma)
320359
         }
321360
     }
322361
 
323362
     // ---- Conditional directive helpers (maintain skip_depth counter) ----
324363
 
325364
     fn push_cond(&mut self, state: CondState) {
326
-        if !matches!(state, CondState::Active) { self.skip_depth += 1; }
365
+        if !matches!(state, CondState::Active) {
366
+            self.skip_depth += 1;
367
+        }
327368
         self.cond_stack.push(state);
328369
     }
329370
 
@@ -341,7 +382,9 @@ impl Preprocessor {
341382
 
342383
     fn pop_cond(&mut self) -> Option<CondState> {
343384
         let popped = self.cond_stack.pop()?;
344
-        if !matches!(popped, CondState::Active) { self.skip_depth -= 1; }
385
+        if !matches!(popped, CondState::Active) {
386
+            self.skip_depth -= 1;
387
+        }
345388
         Some(popped)
346389
     }
347390
 
@@ -355,7 +398,11 @@ impl Preprocessor {
355398
         }
356399
         let defined = self.defines.contains_key(name);
357400
         let condition = if negate { !defined } else { defined };
358
-        self.push_cond(if condition { CondState::Active } else { CondState::Skipping });
401
+        self.push_cond(if condition {
402
+            CondState::Active
403
+        } else {
404
+            CondState::Skipping
405
+        });
359406
         Ok(())
360407
     }
361408
 
@@ -365,14 +412,19 @@ impl Preprocessor {
365412
             return Ok(());
366413
         }
367414
         let val = self.eval_condition(args, filename, line_num)?;
368
-        self.push_cond(if val { CondState::Active } else { CondState::Skipping });
415
+        self.push_cond(if val {
416
+            CondState::Active
417
+        } else {
418
+            CondState::Skipping
419
+        });
369420
         Ok(())
370421
     }
371422
 
372423
     fn do_elif(&mut self, args: &str, filename: &str, line_num: u32) -> Result<(), PreprocError> {
373424
         match self.cond_stack.last().copied() {
374425
             None => Err(PreprocError {
375
-                filename: filename.into(), line: line_num,
426
+                filename: filename.into(),
427
+                line: line_num,
376428
                 msg: "#elif without matching #if".into(),
377429
             }),
378430
             Some(CondState::ParentSkipping) => Ok(()),
@@ -383,7 +435,11 @@ impl Preprocessor {
383435
             Some(CondState::Done) => Ok(()),
384436
             Some(CondState::Skipping) => {
385437
                 let val = self.eval_condition(args, filename, line_num)?;
386
-                self.set_top_cond(if val { CondState::Active } else { CondState::Skipping });
438
+                self.set_top_cond(if val {
439
+                    CondState::Active
440
+                } else {
441
+                    CondState::Skipping
442
+                });
387443
                 Ok(())
388444
             }
389445
         }
@@ -392,7 +448,8 @@ impl Preprocessor {
392448
     fn do_else(&mut self, filename: &str, line_num: u32) -> Result<(), PreprocError> {
393449
         match self.cond_stack.last().copied() {
394450
             None => Err(PreprocError {
395
-                filename: filename.into(), line: line_num,
451
+                filename: filename.into(),
452
+                line: line_num,
396453
                 msg: "#else without matching #if".into(),
397454
             }),
398455
             Some(CondState::ParentSkipping) => Ok(()),
@@ -411,7 +468,8 @@ impl Preprocessor {
411468
     fn do_endif(&mut self, filename: &str, line_num: u32) -> Result<(), PreprocError> {
412469
         if self.pop_cond().is_none() {
413470
             return Err(PreprocError {
414
-                filename: filename.into(), line: line_num,
471
+                filename: filename.into(),
472
+                line: line_num,
415473
                 msg: "#endif without matching #if".into(),
416474
             });
417475
         }
@@ -434,7 +492,8 @@ impl Preprocessor {
434492
                 let rest = &args[paren_pos + 1..];
435493
                 if let Some(close) = rest.find(')') {
436494
                     let params_str = &rest[..close];
437
-                    let mut params: Vec<String> = params_str.split(',')
495
+                    let mut params: Vec<String> = params_str
496
+                        .split(',')
438497
                         .map(|p| p.trim().to_string())
439498
                         .filter(|p| !p.is_empty())
440499
                         .collect();
@@ -495,42 +554,48 @@ impl Preprocessor {
495554
         let args = args.trim();
496555
         let (path_str, search_system) = if let Some(rest) = args.strip_prefix('"') {
497556
             let end = rest.find('"').ok_or_else(|| PreprocError {
498
-                filename: filename.into(), line: line_num,
557
+                filename: filename.into(),
558
+                line: line_num,
499559
                 msg: "unterminated #include string".into(),
500560
             })?;
501561
             (&rest[..end], false)
502562
         } else if let Some(rest) = args.strip_prefix('<') {
503563
             let end = rest.find('>').ok_or_else(|| PreprocError {
504
-                filename: filename.into(), line: line_num,
564
+                filename: filename.into(),
565
+                line: line_num,
505566
                 msg: "unterminated #include <path>".into(),
506567
             })?;
507568
             (&rest[..end], true)
508569
         } else {
509570
             return Err(PreprocError {
510
-                filename: filename.into(), line: line_num,
571
+                filename: filename.into(),
572
+                line: line_num,
511573
                 msg: format!("expected \"file\" or <file> after #include, got: {}", args),
512574
             });
513575
         };
514576
 
515577
         if self.include_depth >= 64 {
516578
             return Err(PreprocError {
517
-                filename: filename.into(), line: line_num,
579
+                filename: filename.into(),
580
+                line: line_num,
518581
                 msg: "include depth limit exceeded (possible recursion)".into(),
519582
             });
520583
         }
521584
 
522585
         // Search for the file.
523
-        let resolved = self.resolve_include(path_str, filename, search_system)
586
+        let resolved = self
587
+            .resolve_include(path_str, filename, search_system)
524588
             .ok_or_else(|| PreprocError {
525
-                filename: filename.into(), line: line_num,
589
+                filename: filename.into(),
590
+                line: line_num,
526591
                 msg: format!("cannot find include file: {}", path_str),
527592
             })?;
528593
 
529
-        let content = std::fs::read_to_string(&resolved)
530
-            .map_err(|e| PreprocError {
531
-                filename: filename.into(), line: line_num,
532
-                msg: format!("reading {}: {}", resolved.display(), e),
533
-            })?;
594
+        let content = std::fs::read_to_string(&resolved).map_err(|e| PreprocError {
595
+            filename: filename.into(),
596
+            line: line_num,
597
+            msg: format!("reading {}: {}", resolved.display(), e),
598
+        })?;
534599
 
535600
         // Save __FILE__ so it's restored after the include returns.
536601
         let saved_file = self.defines.get("__FILE__").cloned();
@@ -571,12 +636,18 @@ impl Preprocessor {
571636
 
572637
     // ---- Condition expression evaluator ----
573638
 
574
-    fn eval_condition(&self, expr: &str, filename: &str, line_num: u32) -> Result<bool, PreprocError> {
639
+    fn eval_condition(
640
+        &self,
641
+        expr: &str,
642
+        filename: &str,
643
+        line_num: u32,
644
+    ) -> Result<bool, PreprocError> {
575645
         // Expand macros in the expression first.
576646
         let expanded = self.expand_condition_macros(expr);
577647
         // Parse and evaluate the expression.
578648
         eval_expr(&expanded).map_err(|msg| PreprocError {
579
-            filename: filename.into(), line: line_num,
649
+            filename: filename.into(),
650
+            line: line_num,
580651
             msg: format!("in #if expression: {}", msg),
581652
         })
582653
     }
@@ -657,7 +728,11 @@ impl Preprocessor {
657728
 
658729
                 if mode == MacroExpandMode::ConditionExpr && ident == "defined" {
659730
                     let (name, new_i) = parse_defined_operand(line, i);
660
-                    result.push_str(if self.defines.contains_key(name) { "1" } else { "0" });
731
+                    result.push_str(if self.defines.contains_key(name) {
732
+                        "1"
733
+                    } else {
734
+                        "0"
735
+                    });
661736
                     i = new_i;
662737
                     continue;
663738
                 }
@@ -671,11 +746,17 @@ impl Preprocessor {
671746
                 if let Some(def) = self.defines.get(ident) {
672747
                     if def.is_function {
673748
                         if i < bytes.len() && bytes[i] == b'(' {
674
-                            if let Some((expanded, new_i)) = self.expand_function_macro(def, line, i) {
749
+                            if let Some((expanded, new_i)) =
750
+                                self.expand_function_macro(def, line, i)
751
+                            {
675752
                                 // Re-expand the result with this macro marked as expanding.
676753
                                 let mut next_expanding = expanding.clone();
677754
                                 next_expanding.insert(ident.to_string());
678
-                                result.push_str(&self.expand_macros_inner(&expanded, &next_expanding, mode));
755
+                                result.push_str(&self.expand_macros_inner(
756
+                                    &expanded,
757
+                                    &next_expanding,
758
+                                    mode,
759
+                                ));
679760
                                 i = new_i;
680761
                                 continue;
681762
                             }
@@ -685,7 +766,11 @@ impl Preprocessor {
685766
                         // Re-expand object macro body with this macro marked as expanding.
686767
                         let mut next_expanding = expanding.clone();
687768
                         next_expanding.insert(ident.to_string());
688
-                        result.push_str(&self.expand_macros_inner(&def.body, &next_expanding, mode));
769
+                        result.push_str(&self.expand_macros_inner(
770
+                            &def.body,
771
+                            &next_expanding,
772
+                            mode,
773
+                        ));
689774
                     }
690775
                 } else {
691776
                     result.push_str(ident);
@@ -700,7 +785,12 @@ impl Preprocessor {
700785
         result
701786
     }
702787
 
703
-    fn expand_function_macro(&self, def: &MacroDef, line: &str, paren_start: usize) -> Option<(String, usize)> {
788
+    fn expand_function_macro(
789
+        &self,
790
+        def: &MacroDef,
791
+        line: &str,
792
+        paren_start: usize,
793
+    ) -> Option<(String, usize)> {
704794
         let bytes = line.as_bytes();
705795
         let mut i = paren_start + 1; // skip '('
706796
         let mut args: Vec<String> = Vec::new();
@@ -709,10 +799,15 @@ impl Preprocessor {
709799
 
710800
         while i < bytes.len() && depth > 0 {
711801
             match bytes[i] {
712
-                b'(' => { depth += 1; current_arg.push('('); }
802
+                b'(' => {
803
+                    depth += 1;
804
+                    current_arg.push('(');
805
+                }
713806
                 b')' => {
714807
                     depth -= 1;
715
-                    if depth > 0 { current_arg.push(')'); }
808
+                    if depth > 0 {
809
+                        current_arg.push(')');
810
+                    }
716811
                 }
717812
                 b',' if depth == 1 => {
718813
                     args.push(current_arg.trim().to_string());
@@ -723,7 +818,9 @@ impl Preprocessor {
723818
             i += 1;
724819
         }
725820
 
726
-        if depth != 0 { return None; }
821
+        if depth != 0 {
822
+            return None;
823
+        }
727824
         args.push(current_arg.trim().to_string());
728825
 
729826
         // Build parameter lookup table.
@@ -753,13 +850,18 @@ impl Preprocessor {
753850
                     id_start += 1;
754851
                 }
755852
                 let mut id_end = id_start;
756
-                while id_end < body_bytes.len() && (body_bytes[id_end].is_ascii_alphanumeric() || body_bytes[id_end] == b'_') {
853
+                while id_end < body_bytes.len()
854
+                    && (body_bytes[id_end].is_ascii_alphanumeric() || body_bytes[id_end] == b'_')
855
+                {
757856
                     id_end += 1;
758857
                 }
759858
                 if id_end > id_start {
760859
                     let id = std::str::from_utf8(&body_bytes[id_start..id_end]).unwrap_or("");
761860
                     if let Some(&pi) = param_map.get(id) {
762
-                        body.push_str(&format!("\"{}\"", args.get(pi).map(|s| s.as_str()).unwrap_or("")));
861
+                        body.push_str(&format!(
862
+                            "\"{}\"",
863
+                            args.get(pi).map(|s| s.as_str()).unwrap_or("")
864
+                        ));
763865
                         bi = id_end;
764866
                         continue;
765867
                     }
@@ -781,7 +883,9 @@ impl Preprocessor {
781883
             // Identifier: check if it's a parameter name.
782884
             if body_bytes[bi].is_ascii_alphabetic() || body_bytes[bi] == b'_' {
783885
                 let id_start = bi;
784
-                while bi < body_bytes.len() && (body_bytes[bi].is_ascii_alphanumeric() || body_bytes[bi] == b'_') {
886
+                while bi < body_bytes.len()
887
+                    && (body_bytes[bi].is_ascii_alphanumeric() || body_bytes[bi] == b'_')
888
+                {
785889
                     bi += 1;
786890
                 }
787891
                 let id = std::str::from_utf8(&body_bytes[id_start..bi]).unwrap_or("");
@@ -870,7 +974,14 @@ fn eval_and(expr: &str) -> Result<i64, String> {
870974
 
871975
 fn eval_comparison(expr: &str) -> Result<i64, String> {
872976
     // Scan right-to-left for left-associative evaluation.
873
-    for (op, op_len) in [("==", 2), ("!=", 2), (">=", 2), ("<=", 2), (">", 1), ("<", 1)] {
977
+    for (op, op_len) in [
978
+        ("==", 2),
979
+        ("!=", 2),
980
+        (">=", 2),
981
+        ("<=", 2),
982
+        (">", 1),
983
+        ("<", 1),
984
+    ] {
874985
         if let Some(pos) = find_op_right(expr, op) {
875986
             let left = eval_comparison(&expr[..pos])?;
876987
             let right = eval_additive(&expr[pos + op_len..])?;
@@ -917,13 +1028,17 @@ fn eval_multiplicative(expr: &str) -> Result<i64, String> {
9171028
     if let Some(pos) = find_op_right(expr, "/") {
9181029
         let left = eval_multiplicative(&expr[..pos])?;
9191030
         let right = eval_unary(&expr[pos + 1..])?;
920
-        if right == 0 { return Err("division by zero in #if expression".into()); }
1031
+        if right == 0 {
1032
+            return Err("division by zero in #if expression".into());
1033
+        }
9211034
         return Ok(left / right);
9221035
     }
9231036
     if let Some(pos) = find_op_right(expr, "%") {
9241037
         let left = eval_multiplicative(&expr[..pos])?;
9251038
         let right = eval_unary(&expr[pos + 1..])?;
926
-        if right == 0 { return Err("modulo by zero in #if expression".into()); }
1039
+        if right == 0 {
1040
+            return Err("modulo by zero in #if expression".into());
1041
+        }
9271042
         return Ok(left % right);
9281043
     }
9291044
     eval_unary(expr)
@@ -954,8 +1069,8 @@ fn eval_primary(expr: &str) -> Result<i64, String> {
9541069
 
9551070
     // Parenthesized expression.
9561071
     if trimmed.starts_with('(') {
957
-        let close = find_matching_paren(trimmed)
958
-            .ok_or("unmatched parenthesis in #if expression")?;
1072
+        let close =
1073
+            find_matching_paren(trimmed).ok_or("unmatched parenthesis in #if expression")?;
9591074
         return eval_or(&trimmed[1..close]);
9601075
     }
9611076
 
@@ -1039,7 +1154,9 @@ fn find_matching_paren(s: &str) -> Option<usize> {
10391154
             '(' => depth += 1,
10401155
             ')' => {
10411156
                 depth -= 1;
1042
-                if depth == 0 { return Some(i); }
1157
+                if depth == 0 {
1158
+                    return Some(i);
1159
+                }
10431160
             }
10441161
             _ => {}
10451162
         }
@@ -1176,8 +1293,9 @@ fn current_datetime() -> (String, String) {
11761293
     // Days since epoch to year/month/day (simplified Gregorian).
11771294
     let (year, month, day) = epoch_days_to_date(days);
11781295
 
1179
-    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
1180
-                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1296
+    let months = [
1297
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1298
+    ];
11811299
     let month_name = months.get(month as usize).unwrap_or(&"???");
11821300
 
11831301
     let date = format!("{} {:2} {}", month_name, day, year);
@@ -1398,7 +1516,10 @@ mod tests {
13981516
 
13991517
     #[test]
14001518
     fn if_arithmetic() {
1401
-        let out = pp_with("#if MAX > 512\nbig\n#else\nsmall\n#endif\n", &[("MAX", "1024")]);
1519
+        let out = pp_with(
1520
+            "#if MAX > 512\nbig\n#else\nsmall\n#endif\n",
1521
+            &[("MAX", "1024")],
1522
+        );
14021523
         assert!(lines(&out).contains(&"big"));
14031524
     }
14041525
 
@@ -1482,7 +1603,11 @@ mod tests {
14821603
         // Regression test: the '' must not cause early string termination.
14831604
         let out = pp_with("x = 'he said ''hello'' there' + FOO\n", &[("FOO", "1")]);
14841605
         assert!(out.contains("'he said ''hello'' there'"), "got: {:?}", out);
1485
-        assert!(out.contains("+ 1"), "FOO after string should expand, got: {:?}", out);
1606
+        assert!(
1607
+            out.contains("+ 1"),
1608
+            "FOO after string should expand, got: {:?}",
1609
+            out
1610
+        );
14861611
     }
14871612
 
14881613
     #[test]
@@ -1669,7 +1794,10 @@ end module
16691794
 
16701795
     #[test]
16711796
     fn if_with_arithmetic() {
1672
-        let out = pp_with("#if MAX + 1 > 512\nbig\n#else\nsmall\n#endif\n", &[("MAX", "1024")]);
1797
+        let out = pp_with(
1798
+            "#if MAX + 1 > 512\nbig\n#else\nsmall\n#endif\n",
1799
+            &[("MAX", "1024")],
1800
+        );
16731801
         assert!(lines(&out).contains(&"big"));
16741802
     }
16751803
 
@@ -1677,26 +1805,44 @@ end module
16771805
     fn if_chained_macros() {
16781806
         // A -> 1, B -> A. #if B should expand B->A->1, evaluating to true.
16791807
         let out = pp_with("#if B\nyes\n#endif\n", &[("A", "1"), ("B", "A")]);
1680
-        assert!(lines(&out).contains(&"yes"), "chained macro in #if failed, got: {:?}", lines(&out));
1808
+        assert!(
1809
+            lines(&out).contains(&"yes"),
1810
+            "chained macro in #if failed, got: {:?}",
1811
+            lines(&out)
1812
+        );
16811813
     }
16821814
 
16831815
     #[test]
16841816
     fn if_chained_three_levels() {
1685
-        let out = pp_with("#if C > 10\nyes\n#endif\n", &[("A", "42"), ("B", "A"), ("C", "B")]);
1686
-        assert!(lines(&out).contains(&"yes"), "3-level chain in #if failed, got: {:?}", lines(&out));
1817
+        let out = pp_with(
1818
+            "#if C > 10\nyes\n#endif\n",
1819
+            &[("A", "42"), ("B", "A"), ("C", "B")],
1820
+        );
1821
+        assert!(
1822
+            lines(&out).contains(&"yes"),
1823
+            "3-level chain in #if failed, got: {:?}",
1824
+            lines(&out)
1825
+        );
16871826
     }
16881827
 
16891828
     #[test]
16901829
     fn if_defined_and_value() {
16911830
         // Common real-world pattern: #if defined(FOO) && FOO > 5
1692
-        let out = pp_with("#if defined(FOO) && FOO > 5\nyes\n#endif\n", &[("FOO", "10")]);
1831
+        let out = pp_with(
1832
+            "#if defined(FOO) && FOO > 5\nyes\n#endif\n",
1833
+            &[("FOO", "10")],
1834
+        );
16931835
         assert!(lines(&out).contains(&"yes"));
16941836
     }
16951837
 
16961838
     #[test]
16971839
     fn if_function_macro_expands() {
16981840
         let out = pp("#define INC(x) ((x) + 1)\n#if INC(41) > 41\nyes\n#endif\n");
1699
-        assert!(lines(&out).contains(&"yes"), "function macro in #if failed, got: {:?}", lines(&out));
1841
+        assert!(
1842
+            lines(&out).contains(&"yes"),
1843
+            "function macro in #if failed, got: {:?}",
1844
+            lines(&out)
1845
+        );
17001846
     }
17011847
 
17021848
     #[test]
@@ -1773,7 +1919,11 @@ end module
17731919
         // After continuation joining, the define body is "    ((a) +      (b))"
17741920
         // with leading/trailing whitespace from the continuation lines.
17751921
         // The body gets trimmed during define processing, so it becomes "((a) +      (b))".
1776
-        assert!(out.contains("((1) +"), "got: {:?}", out.lines().collect::<Vec<_>>());
1922
+        assert!(
1923
+            out.contains("((1) +"),
1924
+            "got: {:?}",
1925
+            out.lines().collect::<Vec<_>>()
1926
+        );
17771927
         assert!(out.contains("(2))"));
17781928
     }
17791929
 
@@ -1781,7 +1931,11 @@ end module
17811931
     fn line_number_correct_after_continuation() {
17821932
         // Lines 1-3 are a continued #define. Line 4 should report __LINE__ = 4.
17831933
         let out = pp("#define M \\\n    42\na\nb = __LINE__\n");
1784
-        assert!(out.contains("b = 4"), "got: {:?}", out.lines().collect::<Vec<_>>());
1934
+        assert!(
1935
+            out.contains("b = 4"),
1936
+            "got: {:?}",
1937
+            out.lines().collect::<Vec<_>>()
1938
+        );
17851939
     }
17861940
 
17871941
     // ---- Self-referencing macro (no infinite loop) ----
@@ -1853,7 +2007,11 @@ deep
18532007
         config.include_paths.push(dir);
18542008
         let src = "#include \"test_pp_include.inc\"\nreal :: x\n";
18552009
         let result = preprocess(src, &config).unwrap();
1856
-        assert!(result.text.contains("integer :: included_var"), "got: {:?}", result.text);
2010
+        assert!(
2011
+            result.text.contains("integer :: included_var"),
2012
+            "got: {:?}",
2013
+            result.text
2014
+        );
18572015
         assert!(result.text.contains("real :: x"));
18582016
     }
18592017
 
@@ -1887,8 +2045,16 @@ deep
18872045
         config.filename = "parent.f90".into();
18882046
         let src = "before = __FILE__\n#include \"test_pp_file_restore.inc\"\nafter = __FILE__\n";
18892047
         let result = preprocess(src, &config).unwrap();
1890
-        assert!(result.text.contains("before = \"parent.f90\""), "got: {:?}", result.text);
1891
-        assert!(result.text.contains("after = \"parent.f90\""), "__FILE__ not restored, got: {:?}", result.text);
2048
+        assert!(
2049
+            result.text.contains("before = \"parent.f90\""),
2050
+            "got: {:?}",
2051
+            result.text
2052
+        );
2053
+        assert!(
2054
+            result.text.contains("after = \"parent.f90\""),
2055
+            "__FILE__ not restored, got: {:?}",
2056
+            result.text
2057
+        );
18922058
     }
18932059
 
18942060
     // ---- Fixed-form awareness ----
@@ -1900,7 +2066,11 @@ deep
19002066
         config.defines.insert("FOO".into(), MacroDef::object("BAR"));
19012067
         let result = preprocess("C     FOO is a comment\n      x = FOO\n", &config).unwrap();
19022068
         // C-line should not have FOO expanded.
1903
-        assert!(result.text.contains("C     FOO is a comment"), "got: {:?}", result.text);
2069
+        assert!(
2070
+            result.text.contains("C     FOO is a comment"),
2071
+            "got: {:?}",
2072
+            result.text
2073
+        );
19042074
         // Continuation line should expand FOO.
19052075
         assert!(result.text.contains("x = BAR"), "got: {:?}", result.text);
19062076
     }
@@ -1911,7 +2081,11 @@ deep
19112081
         config.fixed_form = true;
19122082
         config.defines.insert("FOO".into(), MacroDef::object("BAR"));
19132083
         let result = preprocess("*     FOO is a comment\n", &config).unwrap();
1914
-        assert!(result.text.contains("*     FOO is a comment"), "got: {:?}", result.text);
2084
+        assert!(
2085
+            result.text.contains("*     FOO is a comment"),
2086
+            "got: {:?}",
2087
+            result.text
2088
+        );
19152089
     }
19162090
 
19172091
     // ---- Fortran & continuation ----
@@ -1919,23 +2093,43 @@ deep
19192093
     #[test]
19202094
     fn fortran_ampersand_continuation() {
19212095
         let out = pp_with("x = FOO + &\n    BAR\n", &[("FOO", "1"), ("BAR", "2")]);
1922
-        assert!(out.contains("x = 1 + 2"), "got: {:?}", out.lines().collect::<Vec<_>>());
2096
+        assert!(
2097
+            out.contains("x = 1 + 2"),
2098
+            "got: {:?}",
2099
+            out.lines().collect::<Vec<_>>()
2100
+        );
19232101
     }
19242102
 
19252103
     #[test]
19262104
     fn ampersand_in_string_not_continued() {
19272105
         // & inside a string literal must NOT trigger continuation.
19282106
         let out = pp("x = 'hello &'\ny = 2\n");
1929
-        assert!(out.contains("'hello &'"), "string corrupted, got: {:?}", out.lines().collect::<Vec<_>>());
1930
-        assert!(out.contains("y = 2"), "next line missing, got: {:?}", out.lines().collect::<Vec<_>>());
2107
+        assert!(
2108
+            out.contains("'hello &'"),
2109
+            "string corrupted, got: {:?}",
2110
+            out.lines().collect::<Vec<_>>()
2111
+        );
2112
+        assert!(
2113
+            out.contains("y = 2"),
2114
+            "next line missing, got: {:?}",
2115
+            out.lines().collect::<Vec<_>>()
2116
+        );
19312117
     }
19322118
 
19332119
     #[test]
19342120
     fn ampersand_in_comment_not_continued() {
19352121
         // & after ! comment must NOT trigger continuation.
19362122
         let out = pp("x = 1 ! comment &\ny = 2\n");
1937
-        assert!(out.contains("! comment &"), "comment corrupted, got: {:?}", out.lines().collect::<Vec<_>>());
1938
-        assert!(out.contains("y = 2"), "next line missing, got: {:?}", out.lines().collect::<Vec<_>>());
2123
+        assert!(
2124
+            out.contains("! comment &"),
2125
+            "comment corrupted, got: {:?}",
2126
+            out.lines().collect::<Vec<_>>()
2127
+        );
2128
+        assert!(
2129
+            out.contains("y = 2"),
2130
+            "next line missing, got: {:?}",
2131
+            out.lines().collect::<Vec<_>>()
2132
+        );
19392133
     }
19402134
 
19412135
     // ---- __DATE__ and __TIME__ ----
@@ -1961,7 +2155,11 @@ deep
19612155
         let mut config = PreprocConfig::default();
19622156
         config.filename = "test.f90".into();
19632157
         let result = preprocess("x = __FILE__\n", &config).unwrap();
1964
-        assert!(result.text.contains("\"test.f90\""), "got: {:?}", result.text);
2158
+        assert!(
2159
+            result.text.contains("\"test.f90\""),
2160
+            "got: {:?}",
2161
+            result.text
2162
+        );
19652163
     }
19662164
 
19672165
     // ---- defined without parens ----
@@ -2070,6 +2268,10 @@ deep
20702268
         let result = preprocess("#include \"test_pp_recurse.inc\"\n", &config);
20712269
         assert!(result.is_err());
20722270
         let err = result.unwrap_err();
2073
-        assert!(err.msg.contains("depth") || err.msg.contains("recursion"), "got: {}", err.msg);
2271
+        assert!(
2272
+            err.msg.contains("depth") || err.msg.contains("recursion"),
2273
+            "got: {}",
2274
+            err.msg
2275
+        );
20742276
     }
20752277
 }
src/sema/intrinsic_modules.rsmodified
224 lines changed — click to load
@@ -17,53 +17,78 @@ pub fn register_intrinsic_modules(st: &mut SymbolTable) {
1717
 
1818
 fn builtin_span() -> Span {
1919
     let pos = crate::lexer::Position { line: 0, col: 0 };
20
-    Span { start: pos, end: pos, file_id: 0 }
20
+    Span {
21
+        start: pos,
22
+        end: pos,
23
+        file_id: 0,
24
+    }
2125
 }
2226
 
2327
 fn insert_param(st: &mut SymbolTable, mod_id: ScopeId, name: &str, ti: TypeInfo) {
2428
     insert_param_val(st, mod_id, name, ti, None);
2529
 }
2630
 
27
-fn insert_param_val(st: &mut SymbolTable, mod_id: ScopeId, name: &str, ti: TypeInfo, val: Option<i64>) {
31
+fn insert_param_val(
32
+    st: &mut SymbolTable,
33
+    mod_id: ScopeId,
34
+    name: &str,
35
+    ti: TypeInfo,
36
+    val: Option<i64>,
37
+) {
2838
     let span = builtin_span();
29
-    st.scope_mut(mod_id).symbols.insert(name.to_lowercase(), Symbol {
30
-        name: name.to_string(),
31
-        kind: SymbolKind::Parameter,
32
-        type_info: Some(ti),
33
-        attrs: SymbolAttrs { parameter: true, ..Default::default() },
34
-        defined_at: span,
35
-        scope: mod_id,
36
-        arg_names: vec![],
37
-        const_value: val,
38
-    });
39
+    st.scope_mut(mod_id).symbols.insert(
40
+        name.to_lowercase(),
41
+        Symbol {
42
+            name: name.to_string(),
43
+            kind: SymbolKind::Parameter,
44
+            type_info: Some(ti),
45
+            attrs: SymbolAttrs {
46
+                parameter: true,
47
+                ..Default::default()
48
+            },
49
+            defined_at: span,
50
+            scope: mod_id,
51
+            arg_names: vec![],
52
+            const_value: val,
53
+        },
54
+    );
3955
 }
4056
 
4157
 fn insert_type(st: &mut SymbolTable, mod_id: ScopeId, name: &str) {
4258
     let span = builtin_span();
43
-    st.scope_mut(mod_id).symbols.insert(name.to_lowercase(), Symbol {
44
-        name: name.to_string(),
45
-        kind: SymbolKind::DerivedType,
46
-        type_info: Some(TypeInfo::Derived(name.to_string())),
47
-        attrs: Default::default(),
48
-        defined_at: span,
49
-        scope: mod_id,
50
-        arg_names: vec![],
51
-        const_value: None,
52
-    });
59
+    st.scope_mut(mod_id).symbols.insert(
60
+        name.to_lowercase(),
61
+        Symbol {
62
+            name: name.to_string(),
63
+            kind: SymbolKind::DerivedType,
64
+            type_info: Some(TypeInfo::Derived(name.to_string())),
65
+            attrs: Default::default(),
66
+            defined_at: span,
67
+            scope: mod_id,
68
+            arg_names: vec![],
69
+            const_value: None,
70
+        },
71
+    );
5372
 }
5473
 
5574
 fn insert_proc(st: &mut SymbolTable, mod_id: ScopeId, name: &str) {
5675
     let span = builtin_span();
57
-    st.scope_mut(mod_id).symbols.insert(name.to_lowercase(), Symbol {
58
-        name: name.to_string(),
59
-        kind: SymbolKind::IntrinsicProc,
60
-        type_info: None,
61
-        attrs: SymbolAttrs { intrinsic: true, ..Default::default() },
62
-        defined_at: span,
63
-        scope: mod_id,
64
-        arg_names: vec![],
65
-        const_value: None,
66
-    });
76
+    st.scope_mut(mod_id).symbols.insert(
77
+        name.to_lowercase(),
78
+        Symbol {
79
+            name: name.to_string(),
80
+            kind: SymbolKind::IntrinsicProc,
81
+            type_info: None,
82
+            attrs: SymbolAttrs {
83
+                intrinsic: true,
84
+                ..Default::default()
85
+            },
86
+            defined_at: span,
87
+            scope: mod_id,
88
+            arg_names: vec![],
89
+            const_value: None,
90
+        },
91
+    );
6792
 }
6893
 
6994
 /// Populate the iso_c_binding module scope.
@@ -74,36 +99,65 @@ fn register_iso_c_binding(st: &mut SymbolTable) {
7499
     // Each constant's VALUE is the kind number (e.g., c_int = 4 means kind=4 = 4 bytes).
75100
     let ik = |k: u8| TypeInfo::Integer { kind: Some(k) };
76101
     for (name, kind) in [
77
-        ("c_int", 4u8), ("c_short", 2), ("c_long", 8), ("c_long_long", 8),
102
+        ("c_int", 4u8),
103
+        ("c_short", 2),
104
+        ("c_long", 8),
105
+        ("c_long_long", 8),
78106
         ("c_signed_char", 1),
79
-        ("c_int8_t", 1), ("c_int16_t", 2), ("c_int32_t", 4), ("c_int64_t", 8),
80
-        ("c_size_t", 8), ("c_intptr_t", 8), ("c_ptrdiff_t", 8),
107
+        ("c_int8_t", 1),
108
+        ("c_int16_t", 2),
109
+        ("c_int32_t", 4),
110
+        ("c_int64_t", 8),
111
+        ("c_size_t", 8),
112
+        ("c_intptr_t", 8),
113
+        ("c_ptrdiff_t", 8),
81114
     ] {
82115
         insert_param_val(st, m, name, ik(4), Some(kind as i64));
83116
     }
84117
 
85118
     // ---- Real kind parameters ----
86
-    for (name, kind) in [
87
-        ("c_float", 4u8), ("c_double", 8), ("c_long_double", 8),
88
-    ] {
89
-        insert_param_val(st, m, name, TypeInfo::Integer { kind: Some(4) }, Some(kind as i64));
119
+    for (name, kind) in [("c_float", 4u8), ("c_double", 8), ("c_long_double", 8)] {
120
+        insert_param_val(
121
+            st,
122
+            m,
123
+            name,
124
+            TypeInfo::Integer { kind: Some(4) },
125
+            Some(kind as i64),
126
+        );
90127
     }
91128
 
92129
     // ---- Complex kind parameters ----
93130
     for (name, kind) in [
94
-        ("c_float_complex", 4u8), ("c_double_complex", 8), ("c_long_double_complex", 8),
131
+        ("c_float_complex", 4u8),
132
+        ("c_double_complex", 8),
133
+        ("c_long_double_complex", 8),
95134
     ] {
96
-        insert_param_val(st, m, name, TypeInfo::Integer { kind: Some(4) }, Some(kind as i64));
135
+        insert_param_val(
136
+            st,
137
+            m,
138
+            name,
139
+            TypeInfo::Integer { kind: Some(4) },
140
+            Some(kind as i64),
141
+        );
97142
     }
98143
 
99144
     // ---- Character and logical kinds ----
100145
     // c_char is an integer kind parameter (value = 1), not a character type.
101146
     insert_param_val(st, m, "c_char", ik(4), Some(1));
102
-    insert_param_val(st, m, "c_bool", TypeInfo::Integer { kind: Some(4) }, Some(1));
147
+    insert_param_val(
148
+        st,
149
+        m,
150
+        "c_bool",
151
+        TypeInfo::Integer { kind: Some(4) },
152
+        Some(1),
153
+    );
103154
 
104155
     // ---- Character constants (c_null_char, etc.) ----
105156
     // Each constant's value is its ASCII byte code.
106
-    let ck = TypeInfo::Character { len: Some(1), kind: Some(1) };
157
+    let ck = TypeInfo::Character {
158
+        len: Some(1),
159
+        kind: Some(1),
160
+    };
107161
     for (name, ascii) in [
108162
         ("c_null_char", 0i64),
109163
         ("c_alert", 7),
@@ -126,7 +180,14 @@ fn register_iso_c_binding(st: &mut SymbolTable) {
126180
     insert_param(st, m, "c_null_funptr", ik(8));
127181
 
128182
     // ---- Procedures ----
129
-    for name in ["c_loc", "c_funloc", "c_f_pointer", "c_f_procpointer", "c_associated", "c_sizeof"] {
183
+    for name in [
184
+        "c_loc",
185
+        "c_funloc",
186
+        "c_f_pointer",
187
+        "c_f_procpointer",
188
+        "c_associated",
189
+        "c_sizeof",
190
+    ] {
130191
         insert_proc(st, m, name);
131192
     }
132193
 
@@ -204,10 +265,19 @@ fn register_ieee_stubs(st: &mut SymbolTable) {
204265
                 insert_proc(st, m, "ieee_set_halting_mode");
205266
             }
206267
             "ieee_features" => {
207
-                for feat in ["ieee_datatype", "ieee_denormal", "ieee_divide",
208
-                             "ieee_halting", "ieee_inexact_flag", "ieee_inf",
209
-                             "ieee_invalid_flag", "ieee_nan", "ieee_rounding",
210
-                             "ieee_sqrt", "ieee_underflow_flag"] {
268
+                for feat in [
269
+                    "ieee_datatype",
270
+                    "ieee_denormal",
271
+                    "ieee_divide",
272
+                    "ieee_halting",
273
+                    "ieee_inexact_flag",
274
+                    "ieee_inf",
275
+                    "ieee_invalid_flag",
276
+                    "ieee_nan",
277
+                    "ieee_rounding",
278
+                    "ieee_sqrt",
279
+                    "ieee_underflow_flag",
280
+                ] {
211281
                     insert_param(st, m, feat, TypeInfo::Logical { kind: Some(4) });
212282
                 }
213283
             }
src/sema/mod.rsmodified
14 lines changed — click to load
@@ -3,10 +3,10 @@
33
 //! Symbol tables, scoping, type checking, module resolution,
44
 //! interface validation, and standard conformance checks.
55
 
6
-pub mod symtab;
6
+pub mod amod;
7
+pub mod intrinsic_modules;
78
 pub mod resolve;
9
+pub mod symtab;
10
+pub mod type_layout;
811
 pub mod types;
912
 pub mod validate;
10
-pub mod intrinsic_modules;
11
-pub mod type_layout;
12
-pub mod amod;
src/sema/symtab.rsmodified
193 lines changed — click to load
@@ -4,8 +4,8 @@
44
 //! mechanisms: local declaration, USE association, host association, and
55
 //! IMPORT. Handles implicit typing and case-insensitive lookup.
66
 
7
-use std::collections::HashMap;
87
 use crate::lexer::Span;
8
+use std::collections::HashMap;
99
 
1010
 /// Scope identifier — an index into the SymbolTable's scope list.
1111
 pub type ScopeId = usize;
@@ -30,16 +30,20 @@ impl SymbolTable {
3030
             pending_access: HashMap::new(),
3131
             arg_order: Vec::new(),
3232
         };
33
-        Self { scopes: vec![global], current: 0 }
33
+        Self {
34
+            scopes: vec![global],
35
+            current: 0,
36
+        }
3437
     }
3538
 }
3639
 
3740
 impl Default for SymbolTable {
38
-    fn default() -> Self { Self::new() }
41
+    fn default() -> Self {
42
+        Self::new()
43
+    }
3944
 }
4045
 
4146
 impl SymbolTable {
42
-
4347
     /// Create a new child scope of the current scope.
4448
     pub fn push_scope(&mut self, kind: ScopeKind) -> ScopeId {
4549
         let id = self.scopes.len();
@@ -161,7 +165,10 @@ impl SymbolTable {
161165
             // 2. Direct USE association.
162166
             for assoc in &scope.use_associations {
163167
                 if assoc.local_name == key {
164
-                    if let Some(sym) = self.scopes[assoc.source_scope].symbols.get(&assoc.original_name) {
168
+                    if let Some(sym) = self.scopes[assoc.source_scope]
169
+                        .symbols
170
+                        .get(&assoc.original_name)
171
+                    {
165172
                         if sym.attrs.access != Access::Private || assoc.is_submodule_access {
166173
                             return Some(sym);
167174
                         }
@@ -232,7 +239,10 @@ impl SymbolTable {
232239
         for scope in &self.scopes {
233240
             for assoc in &scope.use_associations {
234241
                 if assoc.local_name == key {
235
-                    if let Some(sym) = self.scopes[assoc.source_scope].symbols.get(&assoc.original_name) {
242
+                    if let Some(sym) = self.scopes[assoc.source_scope]
243
+                        .symbols
244
+                        .get(&assoc.original_name)
245
+                    {
236246
                         return Some(sym);
237247
                     }
238248
                 }
@@ -284,7 +294,10 @@ impl SymbolTable {
284294
     pub fn set_implicit_rule(&mut self, start: char, end: char, itype: ImplicitType) {
285295
         let scope = &mut self.scopes[self.current];
286296
         for c in start..=end {
287
-            scope.implicit_rules.rules.insert(c.to_ascii_lowercase(), itype);
297
+            scope
298
+                .implicit_rules
299
+                .rules
300
+                .insert(c.to_ascii_lowercase(), itype);
288301
         }
289302
     }
290303
 
@@ -336,8 +349,14 @@ impl SymbolTable {
336349
         let key = name.to_lowercase();
337350
         self.scopes.iter().find_map(|s| {
338351
             if let ScopeKind::Module(ref n) = s.kind {
339
-                if n.to_lowercase() == key { Some(s.id) } else { None }
340
-            } else { None }
352
+                if n.to_lowercase() == key {
353
+                    Some(s.id)
354
+                } else {
355
+                    None
356
+                }
357
+            } else {
358
+                None
359
+            }
341360
         })
342361
     }
343362
 }
@@ -509,15 +528,27 @@ impl ImplicitRules {
509528
     /// Standard Fortran default: I-N integer, everything else real.
510529
     pub fn default_fortran() -> Self {
511530
         let mut rules = HashMap::new();
512
-        for c in 'a'..='h' { rules.insert(c, ImplicitType::Real); }
513
-        for c in 'i'..='n' { rules.insert(c, ImplicitType::Integer); }
514
-        for c in 'o'..='z' { rules.insert(c, ImplicitType::Real); }
515
-        Self { none_type: false, none_external: false, rules }
531
+        for c in 'a'..='h' {
532
+            rules.insert(c, ImplicitType::Real);
533
+        }
534
+        for c in 'i'..='n' {
535
+            rules.insert(c, ImplicitType::Integer);
536
+        }
537
+        for c in 'o'..='z' {
538
+            rules.insert(c, ImplicitType::Real);
539
+        }
540
+        Self {
541
+            none_type: false,
542
+            none_external: false,
543
+            rules,
544
+        }
516545
     }
517546
 
518547
     /// Look up the implicit type for a name's first letter.
519548
     pub fn type_for(&self, name: &str) -> Option<ImplicitType> {
520
-        if self.none_type { return None; }
549
+        if self.none_type {
550
+            return None;
551
+        }
521552
         let first = name.chars().next()?.to_ascii_lowercase();
522553
         self.rules.get(&first).copied()
523554
     }
@@ -543,7 +574,11 @@ pub struct SemaError {
543574
 
544575
 impl std::fmt::Display for SemaError {
545576
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546
-        write!(f, "{}:{}: error: {}", self.span.start.line, self.span.start.col, self.msg)
577
+        write!(
578
+            f,
579
+            "{}:{}: error: {}",
580
+            self.span.start.line, self.span.start.col, self.msg
581
+        )
547582
     }
548583
 }
549584
 
@@ -555,7 +590,11 @@ mod tests {
555590
     use crate::lexer::{Position, Span};
556591
 
557592
     fn dummy_span() -> Span {
558
-        Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } }
593
+        Span {
594
+            file_id: 0,
595
+            start: Position { line: 1, col: 1 },
596
+            end: Position { line: 1, col: 1 },
597
+        }
559598
     }
560599
 
561600
     fn make_symbol(name: &str, kind: SymbolKind) -> Symbol {
@@ -596,7 +635,8 @@ mod tests {
596635
     fn case_insensitive_lookup() {
597636
         let mut st = SymbolTable::new();
598637
         st.push_scope(ScopeKind::Program("main".into()));
599
-        st.define(make_symbol("MyVar", SymbolKind::Variable)).unwrap();
638
+        st.define(make_symbol("MyVar", SymbolKind::Variable))
639
+            .unwrap();
600640
         assert!(st.lookup("myvar").is_some());
601641
         assert!(st.lookup("MYVAR").is_some());
602642
         assert!(st.lookup("MyVar").is_some());
@@ -707,7 +747,8 @@ mod tests {
707747
         let mut st = SymbolTable::new();
708748
 
709749
         let mod_scope = st.push_scope(ScopeKind::Module("mymod".into()));
710
-        st.define(make_symbol("original_name", SymbolKind::Variable)).unwrap();
750
+        st.define(make_symbol("original_name", SymbolKind::Variable))
751
+            .unwrap();
711752
         st.pop_scope();
712753
 
713754
         st.push_scope(ScopeKind::Program("main".into()));
@@ -775,11 +816,23 @@ mod tests {
775816
     fn implicit_default_rules() {
776817
         let st = SymbolTable::new();
777818
         // i-n → integer.
778
-        assert_eq!(st.scopes[0].implicit_rules.type_for("index"), Some(ImplicitType::Integer));
779
-        assert_eq!(st.scopes[0].implicit_rules.type_for("jmax"), Some(ImplicitType::Integer));
819
+        assert_eq!(
820
+            st.scopes[0].implicit_rules.type_for("index"),
821
+            Some(ImplicitType::Integer)
822
+        );
823
+        assert_eq!(
824
+            st.scopes[0].implicit_rules.type_for("jmax"),
825
+            Some(ImplicitType::Integer)
826
+        );
780827
         // a-h, o-z → real.
781
-        assert_eq!(st.scopes[0].implicit_rules.type_for("x"), Some(ImplicitType::Real));
782
-        assert_eq!(st.scopes[0].implicit_rules.type_for("alpha"), Some(ImplicitType::Real));
828
+        assert_eq!(
829
+            st.scopes[0].implicit_rules.type_for("x"),
830
+            Some(ImplicitType::Real)
831
+        );
832
+        assert_eq!(
833
+            st.scopes[0].implicit_rules.type_for("alpha"),
834
+            Some(ImplicitType::Real)
835
+        );
783836
     }
784837
 
785838
     #[test]
@@ -797,7 +850,10 @@ mod tests {
797850
         st.push_scope(ScopeKind::Program("main".into()));
798851
         st.set_implicit_rule('a', 'z', ImplicitType::DoublePrecision);
799852
         assert_eq!(st.implicit_type("x"), Some(ImplicitType::DoublePrecision));
800
-        assert_eq!(st.implicit_type("index"), Some(ImplicitType::DoublePrecision));
853
+        assert_eq!(
854
+            st.implicit_type("index"),
855
+            Some(ImplicitType::DoublePrecision)
856
+        );
801857
     }
802858
 
803859
     // ---- Module scope finding ----
src/sema/type_layout.rsmodified
385 lines changed — click to load
@@ -3,8 +3,8 @@
33
 //! Computes field offsets, alignment, and total size for derived types
44
 //! using natural alignment rules (same as C struct layout on ARM64).
55
 
6
-use std::collections::HashMap;
76
 use super::symtab::TypeInfo;
7
+use std::collections::HashMap;
88
 
99
 /// Layout of a single field in a derived type.
1010
 #[derive(Debug, Clone)]
@@ -56,7 +56,9 @@ impl TypeLayout {
5656
     /// Look up a type-bound procedure by method name.
5757
     pub fn bound_proc(&self, name: &str) -> Option<&BoundProc> {
5858
         let key = name.to_lowercase();
59
-        self.bound_procs.iter().find(|p| p.method_name.to_lowercase() == key)
59
+        self.bound_procs
60
+            .iter()
61
+            .find(|p| p.method_name.to_lowercase() == key)
6062
     }
6163
 }
6264
 
@@ -69,7 +71,10 @@ pub struct TypeLayoutRegistry {
6971
 
7072
 impl TypeLayoutRegistry {
7173
     pub fn new() -> Self {
72
-        Self { layouts: HashMap::new(), next_tag: 1 }
74
+        Self {
75
+            layouts: HashMap::new(),
76
+            next_tag: 1,
77
+        }
7378
     }
7479
 
7580
     pub fn alloc_tag(&mut self) -> u64 {
@@ -202,7 +207,11 @@ fn eval_const_int_expr(
202207
                     };
203208
                     match &e.node {
204209
                         Expr::RealLiteral { text, .. } => {
205
-                            Some(if text.contains('d') || text.contains('D') { 8 } else { 4 })
210
+                            Some(if text.contains('d') || text.contains('D') {
211
+                                8
212
+                            } else {
213
+                                4
214
+                            })
206215
                         }
207216
                         Expr::IntegerLiteral { .. } => Some(4),
208217
                         _ => None,
@@ -246,52 +255,47 @@ fn type_spec_to_type_info(
246255
     ts: &crate::ast::decl::TypeSpec,
247256
     const_params: &HashMap<String, i64>,
248257
 ) -> TypeInfo {
249
-    use crate::ast::decl::{TypeSpec, KindSelector, LenSpec};
258
+    use crate::ast::decl::{KindSelector, LenSpec, TypeSpec};
250259
 
251260
     match ts {
252261
         TypeSpec::Integer(kind) => TypeInfo::Integer {
253
-            kind: kind
254
-                .as_ref()
255
-                .and_then(|k| match k {
256
-                    KindSelector::Expr(e) | KindSelector::Star(e) => {
257
-                        eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
258
-                    }
259
-                }),
262
+            kind: kind.as_ref().and_then(|k| match k {
263
+                KindSelector::Expr(e) | KindSelector::Star(e) => {
264
+                    eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
265
+                }
266
+            }),
260267
         },
261268
         TypeSpec::Real(kind) => TypeInfo::Real {
262
-            kind: kind
263
-                .as_ref()
264
-                .and_then(|k| match k {
265
-                    KindSelector::Expr(e) | KindSelector::Star(e) => {
266
-                        eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
267
-                    }
268
-                }),
269
+            kind: kind.as_ref().and_then(|k| match k {
270
+                KindSelector::Expr(e) | KindSelector::Star(e) => {
271
+                    eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
272
+                }
273
+            }),
269274
         },
270275
         TypeSpec::DoublePrecision => TypeInfo::DoublePrecision,
271276
         TypeSpec::Complex(kind) => TypeInfo::Complex {
272
-            kind: kind
273
-                .as_ref()
274
-                .and_then(|k| match k {
275
-                    KindSelector::Expr(e) | KindSelector::Star(e) => {
276
-                        eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
277
-                    }
278
-                }),
277
+            kind: kind.as_ref().and_then(|k| match k {
278
+                KindSelector::Expr(e) | KindSelector::Star(e) => {
279
+                    eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
280
+                }
281
+            }),
279282
         },
280283
         TypeSpec::DoubleComplex => TypeInfo::Complex { kind: Some(8) },
281284
         TypeSpec::Logical(kind) => TypeInfo::Logical {
282
-            kind: kind
283
-                .as_ref()
284
-                .and_then(|k| match k {
285
-                    KindSelector::Expr(e) | KindSelector::Star(e) => {
286
-                        eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
287
-                    }
288
-                }),
285
+            kind: kind.as_ref().and_then(|k| match k {
286
+                KindSelector::Expr(e) | KindSelector::Star(e) => {
287
+                    eval_const_int_expr(e, const_params).and_then(|v| u8::try_from(v).ok())
288
+                }
289
+            }),
289290
         },
290291
         TypeSpec::Character(sel) => {
291
-            let len = sel.as_ref().and_then(|s| s.len.as_ref()).and_then(|l| match l {
292
-                LenSpec::Expr(e) => eval_const_int_expr(e, const_params),
293
-                _ => None,
294
-            });
292
+            let len = sel
293
+                .as_ref()
294
+                .and_then(|s| s.len.as_ref())
295
+                .and_then(|l| match l {
296
+                    LenSpec::Expr(e) => eval_const_int_expr(e, const_params),
297
+                    _ => None,
298
+                });
295299
             let kind = sel
296300
                 .as_ref()
297301
                 .and_then(|s| s.kind.as_ref())
@@ -331,10 +335,21 @@ pub fn compute_layout(
331335
 
332336
     // Process component declarations.
333337
     for decl in components {
334
-        if let crate::ast::decl::Decl::TypeDecl { type_spec, attrs, entities } = &decl.node {
335
-            let is_allocatable = attrs.iter().any(|a| matches!(a, crate::ast::decl::Attribute::Allocatable));
336
-            let is_pointer = attrs.iter().any(|a| matches!(a, crate::ast::decl::Attribute::Pointer));
337
-            let is_target = attrs.iter().any(|a| matches!(a, crate::ast::decl::Attribute::Target));
338
+        if let crate::ast::decl::Decl::TypeDecl {
339
+            type_spec,
340
+            attrs,
341
+            entities,
342
+        } = &decl.node
343
+        {
344
+            let is_allocatable = attrs
345
+                .iter()
346
+                .any(|a| matches!(a, crate::ast::decl::Attribute::Allocatable));
347
+            let is_pointer = attrs
348
+                .iter()
349
+                .any(|a| matches!(a, crate::ast::decl::Attribute::Pointer));
350
+            let is_target = attrs
351
+                .iter()
352
+                .any(|a| matches!(a, crate::ast::decl::Attribute::Target));
338353
 
339354
             let ti = type_spec_to_type_info(type_spec, const_params);
340355
             for entity in entities {
@@ -343,20 +358,22 @@ pub fn compute_layout(
343358
                 } else {
344359
                     eval_explicit_array_dims(entity.array_spec.as_ref(), const_params)
345360
                 };
346
-                let (elem_size, elem_align) = if matches!(
347
-                    &ti,
348
-                    TypeInfo::Character { len: None, .. }
349
-                ) && (is_allocatable || is_pointer) && entity.array_spec.is_none() {
350
-                    (32, 8) // StringDescriptor for deferred-length scalar char components
351
-                } else if is_allocatable || is_pointer {
352
-                    (384, 8) // ArrayDescriptor size for allocatable/pointer components
353
-                } else if let TypeInfo::Derived(ref dname) = ti {
354
-                    registry.get(dname)
355
-                        .map(|l| (l.size, l.align))
356
-                        .unwrap_or((8, 8))
357
-                } else {
358
-                    size_of_type(&ti)
359
-                };
361
+                let (elem_size, elem_align) =
362
+                    if matches!(&ti, TypeInfo::Character { len: None, .. })
363
+                        && (is_allocatable || is_pointer)
364
+                        && entity.array_spec.is_none()
365
+                    {
366
+                        (32, 8) // StringDescriptor for deferred-length scalar char components
367
+                    } else if is_allocatable || is_pointer {
368
+                        (384, 8) // ArrayDescriptor size for allocatable/pointer components
369
+                    } else if let TypeInfo::Derived(ref dname) = ti {
370
+                        registry
371
+                            .get(dname)
372
+                            .map(|l| (l.size, l.align))
373
+                            .unwrap_or((8, 8))
374
+                    } else {
375
+                        size_of_type(&ti)
376
+                    };
360377
                 // Pad to alignment.
361378
                 let padding = (elem_align - (offset % elem_align)) % elem_align;
362379
                 offset += padding;
@@ -392,15 +409,18 @@ pub fn compute_layout(
392409
     }
393410
 
394411
     // Collect type-bound procedure mappings.
395
-    let bound_procs: Vec<BoundProc> = type_bound_procs.iter().map(|tbp| {
396
-        let target = tbp.binding.as_deref().unwrap_or(&tbp.name);
397
-        let nopass = tbp.attrs.iter().any(|a| a.eq_ignore_ascii_case("nopass"));
398
-        BoundProc {
399
-            method_name: tbp.name.clone(),
400
-            target_name: target.to_string(),
401
-            nopass,
402
-        }
403
-    }).collect();
412
+    let bound_procs: Vec<BoundProc> = type_bound_procs
413
+        .iter()
414
+        .map(|tbp| {
415
+            let target = tbp.binding.as_deref().unwrap_or(&tbp.name);
416
+            let nopass = tbp.attrs.iter().any(|a| a.eq_ignore_ascii_case("nopass"));
417
+            BoundProc {
418
+                method_name: tbp.name.clone(),
419
+                target_name: target.to_string(),
420
+                nopass,
421
+            }
422
+        })
423
+        .collect();
404424
 
405425
     TypeLayout {
406426
         name: type_name.to_string(),
@@ -425,7 +445,13 @@ mod tests {
425445
         assert_eq!(size_of_type(&TypeInfo::Real { kind: Some(4) }), (4, 4));
426446
         assert_eq!(size_of_type(&TypeInfo::Real { kind: Some(8) }), (8, 8));
427447
         assert_eq!(size_of_type(&TypeInfo::Logical { kind: Some(4) }), (4, 4));
428
-        assert_eq!(size_of_type(&TypeInfo::Character { len: Some(10), kind: None }), (10, 1));
448
+        assert_eq!(
449
+            size_of_type(&TypeInfo::Character {
450
+                len: Some(10),
451
+                kind: None
452
+            }),
453
+            (10, 1)
454
+        );
429455
         assert_eq!(size_of_type(&TypeInfo::Complex { kind: Some(4) }), (8, 4));
430456
         assert_eq!(size_of_type(&TypeInfo::Complex { kind: Some(8) }), (16, 8));
431457
     }
@@ -437,8 +463,26 @@ mod tests {
437463
             size: 8,
438464
             align: 4,
439465
             fields: vec![
440
-                FieldLayout { name: "x".into(), offset: 0, size: 4, dims: vec![], type_info: TypeInfo::Real { kind: Some(4) }, allocatable: false, pointer: false, target: false },
441
-                FieldLayout { name: "y".into(), offset: 4, size: 4, dims: vec![], type_info: TypeInfo::Real { kind: Some(4) }, allocatable: false, pointer: false, target: false },
466
+                FieldLayout {
467
+                    name: "x".into(),
468
+                    offset: 0,
469
+                    size: 4,
470
+                    dims: vec![],
471
+                    type_info: TypeInfo::Real { kind: Some(4) },
472
+                    allocatable: false,
473
+                    pointer: false,
474
+                    target: false,
475
+                },
476
+                FieldLayout {
477
+                    name: "y".into(),
478
+                    offset: 4,
479
+                    size: 4,
480
+                    dims: vec![],
481
+                    type_info: TypeInfo::Real { kind: Some(4) },
482
+                    allocatable: false,
483
+                    pointer: false,
484
+                    target: false,
485
+                },
442486
             ],
443487
             bound_procs: vec![],
444488
             final_procs: vec![],
@@ -463,9 +507,36 @@ mod tests {
463507
             size: 24,
464508
             align: 8,
465509
             fields: vec![
466
-                FieldLayout { name: "a".into(), offset: 0, size: 1, dims: vec![], type_info: TypeInfo::Integer { kind: Some(1) }, allocatable: false, pointer: false, target: false },
467
-                FieldLayout { name: "b".into(), offset: 8, size: 8, dims: vec![], type_info: TypeInfo::Real { kind: Some(8) }, allocatable: false, pointer: false, target: false },
468
-                FieldLayout { name: "c".into(), offset: 16, size: 4, dims: vec![], type_info: TypeInfo::Integer { kind: Some(4) }, allocatable: false, pointer: false, target: false },
510
+                FieldLayout {
511
+                    name: "a".into(),
512
+                    offset: 0,
513
+                    size: 1,
514
+                    dims: vec![],
515
+                    type_info: TypeInfo::Integer { kind: Some(1) },
516
+                    allocatable: false,
517
+                    pointer: false,
518
+                    target: false,
519
+                },
520
+                FieldLayout {
521
+                    name: "b".into(),
522
+                    offset: 8,
523
+                    size: 8,
524
+                    dims: vec![],
525
+                    type_info: TypeInfo::Real { kind: Some(8) },
526
+                    allocatable: false,
527
+                    pointer: false,
528
+                    target: false,
529
+                },
530
+                FieldLayout {
531
+                    name: "c".into(),
532
+                    offset: 16,
533
+                    size: 4,
534
+                    dims: vec![],
535
+                    type_info: TypeInfo::Integer { kind: Some(4) },
536
+                    allocatable: false,
537
+                    pointer: false,
538
+                    target: false,
539
+                },
469540
             ],
470541
             bound_procs: vec![],
471542
             final_procs: vec![],
@@ -503,18 +574,25 @@ mod tests {
503574
         use crate::ast::decl::*;
504575
         use crate::ast::Spanned;
505576
         let pos = crate::lexer::Position { line: 0, col: 0 };
506
-        let span = crate::lexer::Span { start: pos, end: pos, file_id: 0 };
507
-        Spanned::new(Decl::TypeDecl {
508
-            type_spec: ts,
509
-            attrs: vec![],
510
-            entities: vec![EntityDecl {
511
-                name: name.to_string(),
512
-                array_spec: None,
513
-                char_len: None,
514
-                init: None,
515
-                ptr_init: None,
516
-            }],
517
-        }, span)
577
+        let span = crate::lexer::Span {
578
+            start: pos,
579
+            end: pos,
580
+            file_id: 0,
581
+        };
582
+        Spanned::new(
583
+            Decl::TypeDecl {
584
+                type_spec: ts,
585
+                attrs: vec![],
586
+                entities: vec![EntityDecl {
587
+                    name: name.to_string(),
588
+                    array_spec: None,
589
+                    char_len: None,
590
+                    init: None,
591
+                    ptr_init: None,
592
+                }],
593
+            },
594
+            span,
595
+        )
518596
     }
519597
 
520598
     fn empty_params() -> std::collections::HashMap<String, i64> {
@@ -544,14 +622,22 @@ mod tests {
544622
         // a(1) + 7pad + b(8) = 16
545623
         let reg = TypeLayoutRegistry::new();
546624
         let components = vec![
547
-            make_component("a", crate::ast::decl::TypeSpec::Integer(
548
-                Some(crate::ast::decl::KindSelector::Expr(
625
+            make_component(
626
+                "a",
627
+                crate::ast::decl::TypeSpec::Integer(Some(crate::ast::decl::KindSelector::Expr(
549628
                     crate::ast::Spanned::new(
550
-                        crate::ast::expr::Expr::IntegerLiteral { text: "1".into(), kind: None },
551
-                        crate::lexer::Span { start: crate::lexer::Position { line: 0, col: 0 }, end: crate::lexer::Position { line: 0, col: 0 }, file_id: 0 },
552
-                    )
553
-                ))
554
-            )),
629
+                        crate::ast::expr::Expr::IntegerLiteral {
630
+                            text: "1".into(),
631
+                            kind: None,
632
+                        },
633
+                        crate::lexer::Span {
634
+                            start: crate::lexer::Position { line: 0, col: 0 },
635
+                            end: crate::lexer::Position { line: 0, col: 0 },
636
+                            file_id: 0,
637
+                        },
638
+                    ),
639
+                ))),
640
+            ),
555641
             make_component("b", crate::ast::decl::TypeSpec::DoublePrecision),
556642
         ];
557643
         let layout = compute_layout("padded", &[], &[], &components, None, &reg, &empty_params());
@@ -568,13 +654,24 @@ mod tests {
568654
         // type :: base; integer :: x; end type
569655
         // type, extends(base) :: child; real :: y; end type
570656
         let reg = TypeLayoutRegistry::new();
571
-        let base_comps = vec![make_component("x", crate::ast::decl::TypeSpec::Integer(None))];
572
-        let base_layout = compute_layout("base", &[], &[], &base_comps, None, &reg, &empty_params());
657
+        let base_comps = vec![make_component(
658
+            "x",
659
+            crate::ast::decl::TypeSpec::Integer(None),
660
+        )];
661
+        let base_layout =
662
+            compute_layout("base", &[], &[], &base_comps, None, &reg, &empty_params());
573663
         assert_eq!(base_layout.size, 4);
574664
 
575665
         let child_comps = vec![make_component("y", crate::ast::decl::TypeSpec::Real(None))];
576
-        let child_layout =
577
-            compute_layout("child", &[], &[], &child_comps, Some(&base_layout), &reg, &empty_params());
666
+        let child_layout = compute_layout(
667
+            "child",
668
+            &[],
669
+            &[],
670
+            &child_comps,
671
+            Some(&base_layout),
672
+            &reg,
673
+            &empty_params(),
674
+        );
578675
         assert_eq!(child_layout.fields.len(), 2); // x + y
579676
         assert_eq!(child_layout.field("x").unwrap().offset, 0); // inherited
580677
         assert_eq!(child_layout.field("y").unwrap().offset, 4); // appended
src/sema/types.rsmodified
1836 lines changed — click to load
@@ -6,26 +6,26 @@
66
 /// A Fortran type.
77
 #[derive(Debug, Clone, PartialEq, Eq)]
88
 pub enum FortranType {
9
-    Integer { kind: u8 },        // kind in bytes: 1, 2, 4, 8, 16
10
-    Real { kind: u8 },           // 4 (single), 8 (double), 16 (quad)
11
-    Complex { kind: u8 },        // 4, 8, 16
12
-    Logical { kind: u8 },        // 1, 2, 4, 8
9
+    Integer { kind: u8 }, // kind in bytes: 1, 2, 4, 8, 16
10
+    Real { kind: u8 },    // 4 (single), 8 (double), 16 (quad)
11
+    Complex { kind: u8 }, // 4, 8, 16
12
+    Logical { kind: u8 }, // 1, 2, 4, 8
1313
     Character { kind: u8, len: CharLen },
1414
     Derived { name: String },
15
-    ClassOf { base: String },    // CLASS(t)
16
-    UnlimitedPoly,               // CLASS(*)
17
-    AssumedType,                 // TYPE(*)
18
-    Void,                        // subroutine (no return value)
19
-    Unknown,                     // not yet determined
15
+    ClassOf { base: String }, // CLASS(t)
16
+    UnlimitedPoly,            // CLASS(*)
17
+    AssumedType,              // TYPE(*)
18
+    Void,                     // subroutine (no return value)
19
+    Unknown,                  // not yet determined
2020
 }
2121
 
2222
 /// Character length.
2323
 #[derive(Debug, Clone, PartialEq, Eq)]
2424
 pub enum CharLen {
2525
     Known(i64),
26
-    Assumed,    // len=*
27
-    Deferred,   // len=:
28
-    Unknown,    // runtime expression
26
+    Assumed,  // len=*
27
+    Deferred, // len=:
28
+    Unknown,  // runtime expression
2929
 }
3030
 
3131
 /// Array type information — wraps an element type with rank and shape.
@@ -62,35 +62,59 @@ pub enum Bound {
6262
 
6363
 impl FortranType {
6464
     /// Default integer: integer(4).
65
-    pub fn default_integer() -> Self { Self::Integer { kind: 4 } }
65
+    pub fn default_integer() -> Self {
66
+        Self::Integer { kind: 4 }
67
+    }
6668
     /// Default real: real(4).
67
-    pub fn default_real() -> Self { Self::Real { kind: 4 } }
69
+    pub fn default_real() -> Self {
70
+        Self::Real { kind: 4 }
71
+    }
6872
     /// Default double precision: real(8).
69
-    pub fn double_precision() -> Self { Self::Real { kind: 8 } }
73
+    pub fn double_precision() -> Self {
74
+        Self::Real { kind: 8 }
75
+    }
7076
     /// Default complex: complex(4).
71
-    pub fn default_complex() -> Self { Self::Complex { kind: 4 } }
77
+    pub fn default_complex() -> Self {
78
+        Self::Complex { kind: 4 }
79
+    }
7280
     /// Default logical: logical(4).
73
-    pub fn default_logical() -> Self { Self::Logical { kind: 4 } }
81
+    pub fn default_logical() -> Self {
82
+        Self::Logical { kind: 4 }
83
+    }
7484
     /// Default character: character(1, len=1).
75
-    pub fn default_character() -> Self { Self::Character { kind: 1, len: CharLen::Known(1) } }
85
+    pub fn default_character() -> Self {
86
+        Self::Character {
87
+            kind: 1,
88
+            len: CharLen::Known(1),
89
+        }
90
+    }
7691
 
7792
     /// Is this a numeric type (integer, real, or complex)?
7893
     pub fn is_numeric(&self) -> bool {
79
-        matches!(self, Self::Integer { .. } | Self::Real { .. } | Self::Complex { .. })
94
+        matches!(
95
+            self,
96
+            Self::Integer { .. } | Self::Real { .. } | Self::Complex { .. }
97
+        )
8098
     }
8199
 
82100
     /// Is this a logical type?
83
-    pub fn is_logical(&self) -> bool { matches!(self, Self::Logical { .. }) }
101
+    pub fn is_logical(&self) -> bool {
102
+        matches!(self, Self::Logical { .. })
103
+    }
84104
 
85105
     /// Is this a character type?
86
-    pub fn is_character(&self) -> bool { matches!(self, Self::Character { .. }) }
106
+    pub fn is_character(&self) -> bool {
107
+        matches!(self, Self::Character { .. })
108
+    }
87109
 
88110
     /// Get the kind (size in bytes) for numeric/logical types.
89111
     pub fn kind(&self) -> Option<u8> {
90112
         match self {
91
-            Self::Integer { kind } | Self::Real { kind } |
92
-            Self::Complex { kind } | Self::Logical { kind } |
93
-            Self::Character { kind, .. } => Some(*kind),
113
+            Self::Integer { kind }
114
+            | Self::Real { kind }
115
+            | Self::Complex { kind }
116
+            | Self::Logical { kind }
117
+            | Self::Character { kind, .. } => Some(*kind),
94118
             _ => None,
95119
         }
96120
     }
@@ -125,13 +149,13 @@ pub fn arithmetic_result_type(left: &FortranType, right: &FortranType) -> Option
125149
     //   real + complex → max(kind_a, kind_b)
126150
     let result_rank = left_rank.max(right_rank);
127151
     let result_kind = if left_rank == right_rank {
128
-        left_kind.max(right_kind)  // same type class: max kind
152
+        left_kind.max(right_kind) // same type class: max kind
129153
     } else if left_rank == 1 {
130
-        right_kind  // integer + real/complex: use real/complex kind
154
+        right_kind // integer + real/complex: use real/complex kind
131155
     } else if right_rank == 1 {
132
-        left_kind   // real/complex + integer: use real/complex kind
156
+        left_kind // real/complex + integer: use real/complex kind
133157
     } else {
134
-        left_kind.max(right_kind)  // real + complex: max kind
158
+        left_kind.max(right_kind) // real + complex: max kind
135159
     };
136160
 
137161
     Some(match result_rank {
@@ -151,7 +175,9 @@ pub fn power_result_type(base: &FortranType, exponent: &FortranType) -> Option<F
151175
         return None;
152176
     }
153177
     // If both integer, result is integer with max kind.
154
-    if matches!(base, FortranType::Integer { .. }) && matches!(exponent, FortranType::Integer { .. }) {
178
+    if matches!(base, FortranType::Integer { .. })
179
+        && matches!(exponent, FortranType::Integer { .. })
180
+    {
155181
         let kind = base.kind().unwrap_or(4).max(exponent.kind().unwrap_or(4));
156182
         return Some(FortranType::Integer { kind });
157183
     }
@@ -186,17 +212,23 @@ pub fn concat_result_type(left: &FortranType, right: &FortranType) -> Option<For
186212
         (CharLen::Known(a), CharLen::Known(b)) => CharLen::Known(a + b),
187213
         _ => CharLen::Unknown,
188214
     };
189
-    Some(FortranType::Character { kind: left_kind, len: result_len })
215
+    Some(FortranType::Character {
216
+        kind: left_kind,
217
+        len: result_len,
218
+    })
190219
 }
191220
 
192221
 /// Check if an implicit conversion is needed from `from` to `to`.
193222
 /// Returns None if no conversion needed, or the target type if needed.
194223
 /// Complex→non-complex requires explicit conversion per standard.
195224
 pub fn needs_conversion(from: &FortranType, to: &FortranType) -> Option<FortranType> {
196
-    if from == to { return None; }
225
+    if from == to {
226
+        return None;
227
+    }
197228
     if from.is_numeric() && to.is_numeric() {
198229
         // Complex → non-complex requires explicit conversion (REAL(), INT()).
199
-        if matches!(from, FortranType::Complex { .. }) && !matches!(to, FortranType::Complex { .. }) {
230
+        if matches!(from, FortranType::Complex { .. }) && !matches!(to, FortranType::Complex { .. })
231
+        {
200232
             return None;
201233
         }
202234
         return Some(to.clone());
@@ -207,7 +239,9 @@ pub fn needs_conversion(from: &FortranType, to: &FortranType) -> Option<FortranT
207239
 /// Logical operators require logical operands and produce logical.
208240
 pub fn logical_result_type(operand: &FortranType) -> Option<FortranType> {
209241
     if operand.is_logical() {
210
-        Some(FortranType::Logical { kind: operand.kind().unwrap_or(4) })
242
+        Some(FortranType::Logical {
243
+            kind: operand.kind().unwrap_or(4),
244
+        })
211245
     } else {
212246
         None // Error: logical operator applied to non-logical type
213247
     }
@@ -224,7 +258,11 @@ pub fn binary_logical_result_type(left: &FortranType, right: &FortranType) -> Op
224258
 }
225259
 
226260
 /// Compute the result type of any binary operation.
227
-pub fn binary_op_result_type(op: &crate::ast::expr::BinaryOp, left: &FortranType, right: &FortranType) -> Option<FortranType> {
261
+pub fn binary_op_result_type(
262
+    op: &crate::ast::expr::BinaryOp,
263
+    left: &FortranType,
264
+    right: &FortranType,
265
+) -> Option<FortranType> {
228266
     use crate::ast::expr::BinaryOp;
229267
     match op {
230268
         BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div => {
@@ -232,9 +270,10 @@ pub fn binary_op_result_type(op: &crate::ast::expr::BinaryOp, left: &FortranType
232270
         }
233271
         BinaryOp::Pow => power_result_type(left, right),
234272
         BinaryOp::Concat => concat_result_type(left, right),
235
-        BinaryOp::Eq | BinaryOp::Ne | BinaryOp::Lt | BinaryOp::Le |
236
-        BinaryOp::Gt | BinaryOp::Ge => {
237
-            if (left.is_numeric() && right.is_numeric()) || (left.is_character() && right.is_character()) {
273
+        BinaryOp::Eq | BinaryOp::Ne | BinaryOp::Lt | BinaryOp::Le | BinaryOp::Gt | BinaryOp::Ge => {
274
+            if (left.is_numeric() && right.is_numeric())
275
+                || (left.is_character() && right.is_character())
276
+            {
238277
                 Some(comparison_result_type())
239278
             } else {
240279
                 None
@@ -248,11 +287,18 @@ pub fn binary_op_result_type(op: &crate::ast::expr::BinaryOp, left: &FortranType
248287
 }
249288
 
250289
 /// Compute the result type of a unary operation.
251
-pub fn unary_op_result_type(op: &crate::ast::expr::UnaryOp, operand: &FortranType) -> Option<FortranType> {
290
+pub fn unary_op_result_type(
291
+    op: &crate::ast::expr::UnaryOp,
292
+    operand: &FortranType,
293
+) -> Option<FortranType> {
252294
     use crate::ast::expr::UnaryOp;
253295
     match op {
254296
         UnaryOp::Plus | UnaryOp::Minus => {
255
-            if operand.is_numeric() { Some(operand.clone()) } else { None }
297
+            if operand.is_numeric() {
298
+                Some(operand.clone())
299
+            } else {
300
+                None
301
+            }
256302
         }
257303
         UnaryOp::Not => logical_result_type(operand),
258304
         UnaryOp::Defined(_) => Some(FortranType::Unknown),
@@ -269,7 +315,10 @@ pub enum CallKind {
269315
 }
270316
 
271317
 /// Disambiguate `A(I)` based on symbol table information.
272
-pub fn disambiguate_call(sym_kind: &super::symtab::SymbolKind, has_range_subscript: bool) -> CallKind {
318
+pub fn disambiguate_call(
319
+    sym_kind: &super::symtab::SymbolKind,
320
+    has_range_subscript: bool,
321
+) -> CallKind {
273322
     use super::symtab::SymbolKind;
274323
     match sym_kind {
275324
         SymbolKind::Variable => {
@@ -279,8 +328,10 @@ pub fn disambiguate_call(sym_kind: &super::symtab::SymbolKind, has_range_subscri
279328
                 CallKind::ArrayElement // variable with subscripts → array element
280329
             }
281330
         }
282
-        SymbolKind::Function | SymbolKind::ExternalProc |
283
-        SymbolKind::IntrinsicProc | SymbolKind::ProcedurePointer => CallKind::FunctionCall,
331
+        SymbolKind::Function
332
+        | SymbolKind::ExternalProc
333
+        | SymbolKind::IntrinsicProc
334
+        | SymbolKind::ProcedurePointer => CallKind::FunctionCall,
284335
         SymbolKind::NamedInterface => CallKind::FunctionCall, // generic → function call
285336
         _ => CallKind::Unknown,
286337
     }
@@ -290,11 +341,19 @@ pub fn disambiguate_call(sym_kind: &super::symtab::SymbolKind, has_range_subscri
290341
 pub fn type_info_to_fortran_type(info: &super::symtab::TypeInfo) -> FortranType {
291342
     use super::symtab::TypeInfo;
292343
     match info {
293
-        TypeInfo::Integer { kind } => FortranType::Integer { kind: kind.unwrap_or(4) },
294
-        TypeInfo::Real { kind } => FortranType::Real { kind: kind.unwrap_or(4) },
344
+        TypeInfo::Integer { kind } => FortranType::Integer {
345
+            kind: kind.unwrap_or(4),
346
+        },
347
+        TypeInfo::Real { kind } => FortranType::Real {
348
+            kind: kind.unwrap_or(4),
349
+        },
295350
         TypeInfo::DoublePrecision => FortranType::Real { kind: 8 },
296
-        TypeInfo::Complex { kind } => FortranType::Complex { kind: kind.unwrap_or(4) },
297
-        TypeInfo::Logical { kind } => FortranType::Logical { kind: kind.unwrap_or(4) },
351
+        TypeInfo::Complex { kind } => FortranType::Complex {
352
+            kind: kind.unwrap_or(4),
353
+        },
354
+        TypeInfo::Logical { kind } => FortranType::Logical {
355
+            kind: kind.unwrap_or(4),
356
+        },
298357
         TypeInfo::Character { len, kind } => FortranType::Character {
299358
             kind: kind.unwrap_or(1),
300359
             len: match len {
@@ -327,7 +386,10 @@ pub fn literal_type(expr: &crate::ast::expr::Expr) -> FortranType {
327386
     use crate::ast::expr::Expr;
328387
     match expr {
329388
         Expr::IntegerLiteral { kind, .. } => {
330
-            let k = kind.as_ref().and_then(|s| s.parse::<u8>().ok()).unwrap_or(4);
389
+            let k = kind
390
+                .as_ref()
391
+                .and_then(|s| s.parse::<u8>().ok())
392
+                .unwrap_or(4);
331393
             FortranType::Integer { kind: k }
332394
         }
333395
         Expr::RealLiteral { text, kind, .. } => {
@@ -344,11 +406,20 @@ pub fn literal_type(expr: &crate::ast::expr::Expr) -> FortranType {
344406
             }
345407
         }
346408
         Expr::StringLiteral { kind, value, .. } => {
347
-            let k = kind.as_ref().and_then(|s| s.parse::<u8>().ok()).unwrap_or(1);
348
-            FortranType::Character { kind: k, len: CharLen::Known(value.len() as i64) }
409
+            let k = kind
410
+                .as_ref()
411
+                .and_then(|s| s.parse::<u8>().ok())
412
+                .unwrap_or(1);
413
+            FortranType::Character {
414
+                kind: k,
415
+                len: CharLen::Known(value.len() as i64),
416
+            }
349417
         }
350418
         Expr::LogicalLiteral { kind, .. } => {
351
-            let k = kind.as_ref().and_then(|s| s.parse::<u8>().ok()).unwrap_or(4);
419
+            let k = kind
420
+                .as_ref()
421
+                .and_then(|s| s.parse::<u8>().ok())
422
+                .unwrap_or(4);
352423
             FortranType::Logical { kind: k }
353424
         }
354425
         Expr::ComplexLiteral { .. } => FortranType::default_complex(),
@@ -359,13 +430,19 @@ pub fn literal_type(expr: &crate::ast::expr::Expr) -> FortranType {
359430
 
360431
 /// Compute the type of an expression given a symbol table context.
361432
 /// Returns Unknown for expressions that can't be resolved without more context.
362
-pub fn expr_type(expr: &crate::ast::expr::SpannedExpr, symtab: &super::symtab::SymbolTable) -> FortranType {
433
+pub fn expr_type(
434
+    expr: &crate::ast::expr::SpannedExpr,
435
+    symtab: &super::symtab::SymbolTable,
436
+) -> FortranType {
363437
     use crate::ast::expr::Expr;
364438
     match &expr.node {
365439
         // Literals
366
-        Expr::IntegerLiteral { .. } | Expr::RealLiteral { .. } |
367
-        Expr::StringLiteral { .. } | Expr::LogicalLiteral { .. } |
368
-        Expr::ComplexLiteral { .. } | Expr::BozLiteral { .. } => literal_type(&expr.node),
440
+        Expr::IntegerLiteral { .. }
441
+        | Expr::RealLiteral { .. }
442
+        | Expr::StringLiteral { .. }
443
+        | Expr::LogicalLiteral { .. }
444
+        | Expr::ComplexLiteral { .. }
445
+        | Expr::BozLiteral { .. } => literal_type(&expr.node),
369446
 
370447
         // Name — look up in symbol table
371448
         Expr::Name { name } => {
@@ -401,12 +478,13 @@ pub fn expr_type(expr: &crate::ast::expr::SpannedExpr, symtab: &super::symtab::S
401478
         Expr::FunctionCall { callee, args } => {
402479
             if let Expr::Name { name } = &callee.node {
403480
                 // Check intrinsics first
404
-                let arg_types: Vec<FortranType> = args.iter().map(|a| {
405
-                    match &a.value {
481
+                let arg_types: Vec<FortranType> = args
482
+                    .iter()
483
+                    .map(|a| match &a.value {
406484
                         crate::ast::expr::SectionSubscript::Element(e) => expr_type(e, symtab),
407485
                         crate::ast::expr::SectionSubscript::Range { .. } => FortranType::Unknown,
408
-                    }
409
-                }).collect();
486
+                    })
487
+                    .collect();
410488
 
411489
                 if let Some(result) = intrinsic_result_type(name, &arg_types) {
412490
                     return result;
@@ -432,9 +510,10 @@ pub fn expr_type(expr: &crate::ast::expr::SpannedExpr, symtab: &super::symtab::S
432510
                                 None => FortranType::Unknown,
433511
                             }
434512
                         }
435
-                        CallKind::Substring => {
436
-                            FortranType::Character { kind: 1, len: CharLen::Unknown }
437
-                        }
513
+                        CallKind::Substring => FortranType::Character {
514
+                            kind: 1,
515
+                            len: CharLen::Unknown,
516
+                        },
438517
                         CallKind::Unknown => FortranType::Unknown,
439518
                     }
440519
                 } else {
@@ -495,7 +574,10 @@ pub fn check_arguments(
495574
         if let Some(kw) = keyword {
496575
             seen_keyword = true;
497576
             // Keyword argument — find matching dummy
498
-            if let Some(idx) = dummy_args.iter().position(|d| d.name.eq_ignore_ascii_case(kw)) {
577
+            if let Some(idx) = dummy_args
578
+                .iter()
579
+                .position(|d| d.name.eq_ignore_ascii_case(kw))
580
+            {
499581
                 if matched[idx] {
500582
                     errors.push(format!("duplicate keyword argument '{}'", kw));
501583
                 } else {
@@ -520,7 +602,10 @@ pub fn check_arguments(
520602
                 check_arg_type(&dummy_args[pos], actual_type, &mut errors);
521603
                 pos += 1;
522604
             } else {
523
-                errors.push(format!("too many arguments (expected at most {})", dummy_args.len()));
605
+                errors.push(format!(
606
+                    "too many arguments (expected at most {})",
607
+                    dummy_args.len()
608
+                ));
524609
                 break;
525610
             }
526611
         }
@@ -624,10 +709,8 @@ pub fn intrinsic_result_type(name: &str, args: &[FortranType]) -> Option<Fortran
624709
         "sign" | "mod" | "modulo" => args.first().cloned(),
625710
 
626711
         // Real-valued math.
627
-        "sin" | "cos" | "tan" | "asin" | "acos" | "atan" |
628
-        "exp" | "log" | "log10" | "sqrt" | "atan2" => {
629
-            Some(args.first().cloned().unwrap_or(FortranType::default_real()))
630
-        }
712
+        "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "exp" | "log" | "log10" | "sqrt"
713
+        | "atan2" => Some(args.first().cloned().unwrap_or(FortranType::default_real())),
631714
 
632715
         // Integer-valued.
633716
         "int" | "nint" | "floor" | "ceiling" => Some(FortranType::default_integer()),
@@ -661,10 +744,14 @@ pub fn intrinsic_result_type(name: &str, args: &[FortranType]) -> Option<Fortran
661744
         "any" | "all" => Some(FortranType::default_logical()),
662745
 
663746
         // Character-valued.
664
-        "trim" | "adjustl" | "adjustr" | "repeat" => {
665
-            Some(FortranType::Character { kind: 1, len: CharLen::Unknown })
666
-        }
667
-        "char" | "achar" => Some(FortranType::Character { kind: 1, len: CharLen::Known(1) }),
747
+        "trim" | "adjustl" | "adjustr" | "repeat" => Some(FortranType::Character {
748
+            kind: 1,
749
+            len: CharLen::Unknown,
750
+        }),
751
+        "char" | "achar" => Some(FortranType::Character {
752
+            kind: 1,
753
+            len: CharLen::Known(1),
754
+        }),
668755
 
669756
         // Complex-valued.
670757
         "cmplx" => Some(FortranType::default_complex()),
@@ -683,18 +770,25 @@ pub fn intrinsic_result_type(name: &str, args: &[FortranType]) -> Option<Fortran
683770
 
684771
         // Inquiry intrinsics.
685772
         "huge" | "tiny" | "epsilon" => args.first().cloned(),
686
-        "precision" | "range" | "digits" | "radix" | "exponent" => Some(FortranType::default_integer()),
773
+        "precision" | "range" | "digits" | "radix" | "exponent" => {
774
+            Some(FortranType::default_integer())
775
+        }
687776
         "storage_size" | "c_sizeof" => Some(FortranType::default_integer()),
688777
         "iachar" | "ichar" => Some(FortranType::default_integer()),
689778
 
690779
         // System / misc.
691780
         "command_argument_count" => Some(FortranType::default_integer()),
692781
         "null" => Some(FortranType::Unknown), // null pointer — type from context
693
-        "new_line" => Some(FortranType::Character { kind: 1, len: CharLen::Known(1) }),
782
+        "new_line" => Some(FortranType::Character {
783
+            kind: 1,
784
+            len: CharLen::Known(1),
785
+        }),
694786
         "logical" => Some(FortranType::default_logical()),
695787
 
696788
         // iso_c_binding.
697
-        "c_loc" | "c_funloc" => Some(FortranType::Derived { name: "c_ptr".into() }),
789
+        "c_loc" | "c_funloc" => Some(FortranType::Derived {
790
+            name: "c_ptr".into(),
791
+        }),
698792
         "c_associated" => Some(FortranType::default_logical()),
699793
 
700794
         // Status inquiry.
@@ -715,7 +809,8 @@ mod tests {
715809
         let result = arithmetic_result_type(
716810
             &FortranType::Integer { kind: 4 },
717811
             &FortranType::Integer { kind: 4 },
718
-        ).unwrap();
812
+        )
813
+        .unwrap();
719814
         assert_eq!(result, FortranType::Integer { kind: 4 });
720815
     }
721816
 
@@ -724,7 +819,8 @@ mod tests {
724819
         let result = arithmetic_result_type(
725820
             &FortranType::Integer { kind: 4 },
726821
             &FortranType::Real { kind: 4 },
727
-        ).unwrap();
822
+        )
823
+        .unwrap();
728824
         assert_eq!(result, FortranType::Real { kind: 4 });
729825
     }
730826
 
@@ -733,7 +829,8 @@ mod tests {
733829
         let result = arithmetic_result_type(
734830
             &FortranType::Real { kind: 4 },
735831
             &FortranType::Complex { kind: 4 },
736
-        ).unwrap();
832
+        )
833
+        .unwrap();
737834
         assert_eq!(result, FortranType::Complex { kind: 4 });
738835
     }
739836
 
@@ -742,7 +839,8 @@ mod tests {
742839
         let result = arithmetic_result_type(
743840
             &FortranType::Integer { kind: 4 },
744841
             &FortranType::Real { kind: 8 },
745
-        ).unwrap();
842
+        )
843
+        .unwrap();
746844
         assert_eq!(result, FortranType::Real { kind: 8 });
747845
     }
748846
 
@@ -751,7 +849,8 @@ mod tests {
751849
         let result = arithmetic_result_type(
752850
             &FortranType::Integer { kind: 4 },
753851
             &FortranType::Integer { kind: 8 },
754
-        ).unwrap();
852
+        )
853
+        .unwrap();
755854
         assert_eq!(result, FortranType::Integer { kind: 8 });
756855
     }
757856
 
@@ -760,7 +859,8 @@ mod tests {
760859
         assert!(arithmetic_result_type(
761860
             &FortranType::default_logical(),
762861
             &FortranType::default_integer(),
763
-        ).is_none());
862
+        )
863
+        .is_none());
764864
     }
765865
 
766866
     // ---- Power ----
@@ -770,7 +870,8 @@ mod tests {
770870
         let result = power_result_type(
771871
             &FortranType::Integer { kind: 4 },
772872
             &FortranType::Integer { kind: 4 },
773
-        ).unwrap();
873
+        )
874
+        .unwrap();
774875
         assert_eq!(result, FortranType::Integer { kind: 4 });
775876
     }
776877
 
@@ -779,7 +880,8 @@ mod tests {
779880
         let result = power_result_type(
780881
             &FortranType::Real { kind: 8 },
781882
             &FortranType::Integer { kind: 4 },
782
-        ).unwrap();
883
+        )
884
+        .unwrap();
783885
         assert_eq!(result, FortranType::Real { kind: 8 });
784886
     }
785887
 
@@ -789,7 +891,8 @@ mod tests {
789891
         let result = power_result_type(
790892
             &FortranType::Integer { kind: 4 },
791893
             &FortranType::Complex { kind: 8 },
792
-        ).unwrap();
894
+        )
895
+        .unwrap();
793896
         assert_eq!(result, FortranType::Complex { kind: 8 });
794897
     }
795898
 
@@ -805,18 +908,35 @@ mod tests {
805908
     #[test]
806909
     fn concat_known_lengths() {
807910
         let result = concat_result_type(
808
-            &FortranType::Character { kind: 1, len: CharLen::Known(5) },
809
-            &FortranType::Character { kind: 1, len: CharLen::Known(3) },
810
-        ).unwrap();
811
-        assert_eq!(result, FortranType::Character { kind: 1, len: CharLen::Known(8) });
911
+            &FortranType::Character {
912
+                kind: 1,
913
+                len: CharLen::Known(5),
914
+            },
915
+            &FortranType::Character {
916
+                kind: 1,
917
+                len: CharLen::Known(3),
918
+            },
919
+        )
920
+        .unwrap();
921
+        assert_eq!(
922
+            result,
923
+            FortranType::Character {
924
+                kind: 1,
925
+                len: CharLen::Known(8)
926
+            }
927
+        );
812928
     }
813929
 
814930
     #[test]
815931
     fn concat_non_character_returns_none() {
816932
         assert!(concat_result_type(
817933
             &FortranType::default_integer(),
818
-            &FortranType::Character { kind: 1, len: CharLen::Known(5) },
819
-        ).is_none());
934
+            &FortranType::Character {
935
+                kind: 1,
936
+                len: CharLen::Known(5)
937
+            },
938
+        )
939
+        .is_none());
820940
     }
821941
 
822942
     // ---- Conversion ----
@@ -826,7 +946,8 @@ mod tests {
826946
         assert!(needs_conversion(
827947
             &FortranType::Integer { kind: 4 },
828948
             &FortranType::Integer { kind: 4 },
829
-        ).is_none());
949
+        )
950
+        .is_none());
830951
     }
831952
 
832953
     #[test]
@@ -834,7 +955,8 @@ mod tests {
834955
         let conv = needs_conversion(
835956
             &FortranType::Integer { kind: 4 },
836957
             &FortranType::Real { kind: 4 },
837
-        ).unwrap();
958
+        )
959
+        .unwrap();
838960
         assert_eq!(conv, FortranType::Real { kind: 4 });
839961
     }
840962
 
@@ -860,9 +982,14 @@ mod tests {
860982
 
861983
     #[test]
862984
     fn len_returns_integer() {
863
-        let result = intrinsic_result_type("len", &[
864
-            FortranType::Character { kind: 1, len: CharLen::Known(10) }
865
-        ]).unwrap();
985
+        let result = intrinsic_result_type(
986
+            "len",
987
+            &[FortranType::Character {
988
+                kind: 1,
989
+                len: CharLen::Known(10),
990
+            }],
991
+        )
992
+        .unwrap();
866993
         assert_eq!(result, FortranType::default_integer());
867994
     }
868995
 
@@ -874,15 +1001,22 @@ mod tests {
8741001
 
8751002
     #[test]
8761003
     fn trim_returns_character() {
877
-        let result = intrinsic_result_type("trim", &[
878
-            FortranType::Character { kind: 1, len: CharLen::Known(20) }
879
-        ]).unwrap();
1004
+        let result = intrinsic_result_type(
1005
+            "trim",
1006
+            &[FortranType::Character {
1007
+                kind: 1,
1008
+                len: CharLen::Known(20),
1009
+            }],
1010
+        )
1011
+        .unwrap();
8801012
         assert!(result.is_character());
8811013
     }
8821014
 
8831015
     #[test]
8841016
     fn unknown_intrinsic_returns_none() {
885
-        assert!(intrinsic_result_type("nonexistent_func", &[FortranType::default_integer()]).is_none());
1017
+        assert!(
1018
+            intrinsic_result_type("nonexistent_func", &[FortranType::default_integer()]).is_none()
1019
+        );
8861020
     }
8871021
 
8881022
     // ---- Binary op result type ----
@@ -894,7 +1028,8 @@ mod tests {
8941028
             &BinaryOp::Add,
8951029
             &FortranType::Integer { kind: 4 },
8961030
             &FortranType::Real { kind: 8 },
897
-        ).unwrap();
1031
+        )
1032
+        .unwrap();
8981033
         assert_eq!(result, FortranType::Real { kind: 8 });
8991034
     }
9001035
 
@@ -905,7 +1040,8 @@ mod tests {
9051040
             &BinaryOp::Pow,
9061041
             &FortranType::Real { kind: 4 },
9071042
             &FortranType::Integer { kind: 4 },
908
-        ).unwrap();
1043
+        )
1044
+        .unwrap();
9091045
         assert_eq!(result, FortranType::Real { kind: 4 });
9101046
     }
9111047
 
@@ -914,10 +1050,23 @@ mod tests {
9141050
         use crate::ast::expr::BinaryOp;
9151051
         let result = binary_op_result_type(
9161052
             &BinaryOp::Concat,
917
-            &FortranType::Character { kind: 1, len: CharLen::Known(3) },
918
-            &FortranType::Character { kind: 1, len: CharLen::Known(4) },
919
-        ).unwrap();
920
-        assert_eq!(result, FortranType::Character { kind: 1, len: CharLen::Known(7) });
1053
+            &FortranType::Character {
1054
+                kind: 1,
1055
+                len: CharLen::Known(3),
1056
+            },
1057
+            &FortranType::Character {
1058
+                kind: 1,
1059
+                len: CharLen::Known(4),
1060
+            },
1061
+        )
1062
+        .unwrap();
1063
+        assert_eq!(
1064
+            result,
1065
+            FortranType::Character {
1066
+                kind: 1,
1067
+                len: CharLen::Known(7)
1068
+            }
1069
+        );
9211070
     }
9221071
 
9231072
     #[test]
@@ -927,7 +1076,8 @@ mod tests {
9271076
             &BinaryOp::Eq,
9281077
             &FortranType::Integer { kind: 4 },
9291078
             &FortranType::Real { kind: 4 },
930
-        ).unwrap();
1079
+        )
1080
+        .unwrap();
9311081
         assert_eq!(result, FortranType::default_logical());
9321082
     }
9331083
 
@@ -936,9 +1086,16 @@ mod tests {
9361086
         use crate::ast::expr::BinaryOp;
9371087
         let result = binary_op_result_type(
9381088
             &BinaryOp::Lt,
939
-            &FortranType::Character { kind: 1, len: CharLen::Known(5) },
940
-            &FortranType::Character { kind: 1, len: CharLen::Known(5) },
941
-        ).unwrap();
1089
+            &FortranType::Character {
1090
+                kind: 1,
1091
+                len: CharLen::Known(5),
1092
+            },
1093
+            &FortranType::Character {
1094
+                kind: 1,
1095
+                len: CharLen::Known(5),
1096
+            },
1097
+        )
1098
+        .unwrap();
9421099
         assert_eq!(result, FortranType::default_logical());
9431100
     }
9441101
 
@@ -948,8 +1105,12 @@ mod tests {
9481105
         assert!(binary_op_result_type(
9491106
             &BinaryOp::Eq,
9501107
             &FortranType::Integer { kind: 4 },
951
-            &FortranType::Character { kind: 1, len: CharLen::Known(3) },
952
-        ).is_none());
1108
+            &FortranType::Character {
1109
+                kind: 1,
1110
+                len: CharLen::Known(3)
1111
+            },
1112
+        )
1113
+        .is_none());
9531114
     }
9541115
 
9551116
     #[test]
@@ -959,7 +1120,8 @@ mod tests {
9591120
             &BinaryOp::And,
9601121
             &FortranType::Logical { kind: 4 },
9611122
             &FortranType::Logical { kind: 4 },
962
-        ).unwrap();
1123
+        )
1124
+        .unwrap();
9631125
         assert_eq!(result, FortranType::Logical { kind: 4 });
9641126
     }
9651127
 
@@ -970,7 +1132,8 @@ mod tests {
9701132
             &BinaryOp::And,
9711133
             &FortranType::Integer { kind: 4 },
9721134
             &FortranType::Logical { kind: 4 },
973
-        ).is_none());
1135
+        )
1136
+        .is_none());
9741137
     }
9751138
 
9761139
     #[test]
@@ -980,7 +1143,8 @@ mod tests {
9801143
             &BinaryOp::Or,
9811144
             &FortranType::Logical { kind: 1 },
9821145
             &FortranType::Logical { kind: 4 },
983
-        ).unwrap();
1146
+        )
1147
+        .unwrap();
9841148
         assert_eq!(result, FortranType::Logical { kind: 4 });
9851149
     }
9861150
 
@@ -991,7 +1155,8 @@ mod tests {
9911155
             &BinaryOp::Defined("cross".into()),
9921156
             &FortranType::default_real(),
9931157
             &FortranType::default_real(),
994
-        ).unwrap();
1158
+        )
1159
+        .unwrap();
9951160
         assert_eq!(result, FortranType::Unknown);
9961161
     }
9971162
 
@@ -1000,39 +1165,28 @@ mod tests {
10001165
     #[test]
10011166
     fn unary_minus_real() {
10021167
         use crate::ast::expr::UnaryOp;
1003
-        let result = unary_op_result_type(
1004
-            &UnaryOp::Minus,
1005
-            &FortranType::Real { kind: 8 },
1006
-        ).unwrap();
1168
+        let result = unary_op_result_type(&UnaryOp::Minus, &FortranType::Real { kind: 8 }).unwrap();
10071169
         assert_eq!(result, FortranType::Real { kind: 8 });
10081170
     }
10091171
 
10101172
     #[test]
10111173
     fn unary_plus_non_numeric_returns_none() {
10121174
         use crate::ast::expr::UnaryOp;
1013
-        assert!(unary_op_result_type(
1014
-            &UnaryOp::Plus,
1015
-            &FortranType::default_logical(),
1016
-        ).is_none());
1175
+        assert!(unary_op_result_type(&UnaryOp::Plus, &FortranType::default_logical(),).is_none());
10171176
     }
10181177
 
10191178
     #[test]
10201179
     fn unary_not_logical() {
10211180
         use crate::ast::expr::UnaryOp;
1022
-        let result = unary_op_result_type(
1023
-            &UnaryOp::Not,
1024
-            &FortranType::Logical { kind: 4 },
1025
-        ).unwrap();
1181
+        let result =
1182
+            unary_op_result_type(&UnaryOp::Not, &FortranType::Logical { kind: 4 }).unwrap();
10261183
         assert_eq!(result, FortranType::Logical { kind: 4 });
10271184
     }
10281185
 
10291186
     #[test]
10301187
     fn unary_not_non_logical_returns_none() {
10311188
         use crate::ast::expr::UnaryOp;
1032
-        assert!(unary_op_result_type(
1033
-            &UnaryOp::Not,
1034
-            &FortranType::Integer { kind: 4 },
1035
-        ).is_none());
1189
+        assert!(unary_op_result_type(&UnaryOp::Not, &FortranType::Integer { kind: 4 },).is_none());
10361190
     }
10371191
 
10381192
     // ---- Disambiguation ----
@@ -1040,43 +1194,64 @@ mod tests {
10401194
     #[test]
10411195
     fn disambiguate_variable_element() {
10421196
         use super::super::symtab::SymbolKind;
1043
-        assert_eq!(disambiguate_call(&SymbolKind::Variable, false), CallKind::ArrayElement);
1197
+        assert_eq!(
1198
+            disambiguate_call(&SymbolKind::Variable, false),
1199
+            CallKind::ArrayElement
1200
+        );
10441201
     }
10451202
 
10461203
     #[test]
10471204
     fn disambiguate_variable_range_is_substring() {
10481205
         use super::super::symtab::SymbolKind;
1049
-        assert_eq!(disambiguate_call(&SymbolKind::Variable, true), CallKind::Substring);
1206
+        assert_eq!(
1207
+            disambiguate_call(&SymbolKind::Variable, true),
1208
+            CallKind::Substring
1209
+        );
10501210
     }
10511211
 
10521212
     #[test]
10531213
     fn disambiguate_function() {
10541214
         use super::super::symtab::SymbolKind;
1055
-        assert_eq!(disambiguate_call(&SymbolKind::Function, false), CallKind::FunctionCall);
1215
+        assert_eq!(
1216
+            disambiguate_call(&SymbolKind::Function, false),
1217
+            CallKind::FunctionCall
1218
+        );
10561219
     }
10571220
 
10581221
     #[test]
10591222
     fn disambiguate_external_proc() {
10601223
         use super::super::symtab::SymbolKind;
1061
-        assert_eq!(disambiguate_call(&SymbolKind::ExternalProc, false), CallKind::FunctionCall);
1224
+        assert_eq!(
1225
+            disambiguate_call(&SymbolKind::ExternalProc, false),
1226
+            CallKind::FunctionCall
1227
+        );
10621228
     }
10631229
 
10641230
     #[test]
10651231
     fn disambiguate_intrinsic_proc() {
10661232
         use super::super::symtab::SymbolKind;
1067
-        assert_eq!(disambiguate_call(&SymbolKind::IntrinsicProc, true), CallKind::FunctionCall);
1233
+        assert_eq!(
1234
+            disambiguate_call(&SymbolKind::IntrinsicProc, true),
1235
+            CallKind::FunctionCall
1236
+        );
10681237
     }
10691238
 
10701239
     #[test]
10711240
     fn disambiguate_named_interface() {
10721241
         use super::super::symtab::SymbolKind;
1073
-        assert_eq!(disambiguate_call(&SymbolKind::NamedInterface, false), CallKind::FunctionCall);
1242
+        assert_eq!(
1243
+            disambiguate_call(&SymbolKind::NamedInterface, false),
1244
+            CallKind::FunctionCall
1245
+        );
10741246
     }
10751247
 
10761248
     #[test]
10771249
     fn disambiguate_unknown_kind() {
10781250
         use super::super::symtab::SymbolKind;
1079
-        assert_eq!(disambiguate_call(&SymbolKind::Module, false), CallKind::Unknown);
1251
+        assert_eq!(
1252
+            disambiguate_call(&SymbolKind::Module, false),
1253
+            CallKind::Unknown
1254
+        );
10801255
     }
10811256
 
10821257
     // ---- TypeInfo → FortranType conversion ----
@@ -1112,8 +1287,14 @@ mod tests {
11121287
     fn type_info_character_with_len() {
11131288
         use super::super::symtab::TypeInfo;
11141289
         assert_eq!(
1115
-            type_info_to_fortran_type(&TypeInfo::Character { len: Some(10), kind: None }),
1116
-            FortranType::Character { kind: 1, len: CharLen::Known(10) }
1290
+            type_info_to_fortran_type(&TypeInfo::Character {
1291
+                len: Some(10),
1292
+                kind: None
1293
+            }),
1294
+            FortranType::Character {
1295
+                kind: 1,
1296
+                len: CharLen::Known(10)
1297
+            }
11171298
         );
11181299
     }
11191300
 
@@ -1122,7 +1303,9 @@ mod tests {
11221303
         use super::super::symtab::TypeInfo;
11231304
         assert_eq!(
11241305
             type_info_to_fortran_type(&TypeInfo::Derived("point".into())),
1125
-            FortranType::Derived { name: "point".into() }
1306
+            FortranType::Derived {
1307
+                name: "point".into()
1308
+            }
11261309
         );
11271310
     }
11281311
 
@@ -1141,7 +1324,10 @@ mod tests {
11411324
     fn literal_type_integer() {
11421325
         use crate::ast::expr::Expr;
11431326
         assert_eq!(
1144
-            literal_type(&Expr::IntegerLiteral { text: "42".into(), kind: None }),
1327
+            literal_type(&Expr::IntegerLiteral {
1328
+                text: "42".into(),
1329
+                kind: None
1330
+            }),
11451331
             FortranType::Integer { kind: 4 }
11461332
         );
11471333
     }
@@ -1150,7 +1336,10 @@ mod tests {
11501336
     fn literal_type_integer_kind8() {
11511337
         use crate::ast::expr::Expr;
11521338
         assert_eq!(
1153
-            literal_type(&Expr::IntegerLiteral { text: "42".into(), kind: Some("8".into()) }),
1339
+            literal_type(&Expr::IntegerLiteral {
1340
+                text: "42".into(),
1341
+                kind: Some("8".into())
1342
+            }),
11541343
             FortranType::Integer { kind: 8 }
11551344
         );
11561345
     }
@@ -1159,7 +1348,10 @@ mod tests {
11591348
     fn literal_type_real_default() {
11601349
         use crate::ast::expr::Expr;
11611350
         assert_eq!(
1162
-            literal_type(&Expr::RealLiteral { text: "3.14".into(), kind: None }),
1351
+            literal_type(&Expr::RealLiteral {
1352
+                text: "3.14".into(),
1353
+                kind: None
1354
+            }),
11631355
             FortranType::Real { kind: 4 }
11641356
         );
11651357
     }
@@ -1168,7 +1360,10 @@ mod tests {
11681360
     fn literal_type_real_d_exponent() {
11691361
         use crate::ast::expr::Expr;
11701362
         assert_eq!(
1171
-            literal_type(&Expr::RealLiteral { text: "1.0d0".into(), kind: None }),
1363
+            literal_type(&Expr::RealLiteral {
1364
+                text: "1.0d0".into(),
1365
+                kind: None
1366
+            }),
11721367
             FortranType::Real { kind: 8 }
11731368
         );
11741369
     }
@@ -1177,8 +1372,14 @@ mod tests {
11771372
     fn literal_type_string() {
11781373
         use crate::ast::expr::Expr;
11791374
         assert_eq!(
1180
-            literal_type(&Expr::StringLiteral { value: "hello".into(), kind: None }),
1181
-            FortranType::Character { kind: 1, len: CharLen::Known(5) }
1375
+            literal_type(&Expr::StringLiteral {
1376
+                value: "hello".into(),
1377
+                kind: None
1378
+            }),
1379
+            FortranType::Character {
1380
+                kind: 1,
1381
+                len: CharLen::Known(5)
1382
+            }
11821383
         );
11831384
     }
11841385
 
@@ -1186,7 +1387,10 @@ mod tests {
11861387
     fn literal_type_logical() {
11871388
         use crate::ast::expr::Expr;
11881389
         assert_eq!(
1189
-            literal_type(&Expr::LogicalLiteral { value: true, kind: None }),
1390
+            literal_type(&Expr::LogicalLiteral {
1391
+                value: true,
1392
+                kind: None
1393
+            }),
11901394
             FortranType::Logical { kind: 4 }
11911395
         );
11921396
     }
@@ -1197,20 +1401,34 @@ mod tests {
11971401
     fn expr_type_integer_literal() {
11981402
         use crate::ast::expr::Expr;
11991403
         use crate::ast::Spanned;
1200
-        use crate::lexer::{Span, Position};
1201
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1202
-        let expr = Spanned::new(Expr::IntegerLiteral { text: "42".into(), kind: None }, span);
1404
+        use crate::lexer::{Position, Span};
1405
+        let span = Span {
1406
+            file_id: 0,
1407
+            start: Position { line: 1, col: 1 },
1408
+            end: Position { line: 1, col: 1 },
1409
+        };
1410
+        let expr = Spanned::new(
1411
+            Expr::IntegerLiteral {
1412
+                text: "42".into(),
1413
+                kind: None,
1414
+            },
1415
+            span,
1416
+        );
12031417
         let st = super::super::symtab::SymbolTable::new();
12041418
         assert_eq!(expr_type(&expr, &st), FortranType::Integer { kind: 4 });
12051419
     }
12061420
 
12071421
     #[test]
12081422
     fn expr_type_name_lookup() {
1423
+        use super::super::symtab::*;
12091424
         use crate::ast::expr::Expr;
12101425
         use crate::ast::Spanned;
1211
-        use crate::lexer::{Span, Position};
1212
-        use super::super::symtab::*;
1213
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1426
+        use crate::lexer::{Position, Span};
1427
+        let span = Span {
1428
+            file_id: 0,
1429
+            start: Position { line: 1, col: 1 },
1430
+            end: Position { line: 1, col: 1 },
1431
+        };
12141432
 
12151433
         let mut st = SymbolTable::new();
12161434
         st.push_scope(ScopeKind::Program("main".into()));
@@ -1223,7 +1441,8 @@ mod tests {
12231441
             scope: 0,
12241442
             arg_names: vec![],
12251443
             const_value: None,
1226
-        }).unwrap();
1444
+        })
1445
+        .unwrap();
12271446
 
12281447
         let expr = Spanned::new(Expr::Name { name: "x".into() }, span);
12291448
         assert_eq!(expr_type(&expr, &st), FortranType::Real { kind: 8 });
@@ -1231,11 +1450,15 @@ mod tests {
12311450
 
12321451
     #[test]
12331452
     fn expr_type_name_implicit() {
1453
+        use super::super::symtab::*;
12341454
         use crate::ast::expr::Expr;
12351455
         use crate::ast::Spanned;
1236
-        use crate::lexer::{Span, Position};
1237
-        use super::super::symtab::*;
1238
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1456
+        use crate::lexer::{Position, Span};
1457
+        let span = Span {
1458
+            file_id: 0,
1459
+            start: Position { line: 1, col: 1 },
1460
+            end: Position { line: 1, col: 1 },
1461
+        };
12391462
 
12401463
         let mut st = SymbolTable::new();
12411464
         st.push_scope(ScopeKind::Program("main".into()));
@@ -1246,15 +1469,38 @@ mod tests {
12461469
 
12471470
     #[test]
12481471
     fn expr_type_binary_add() {
1249
-        use crate::ast::expr::{Expr, BinaryOp};
1472
+        use crate::ast::expr::{BinaryOp, Expr};
12501473
         use crate::ast::Spanned;
1251
-        use crate::lexer::{Span, Position};
1252
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1474
+        use crate::lexer::{Position, Span};
1475
+        let span = Span {
1476
+            file_id: 0,
1477
+            start: Position { line: 1, col: 1 },
1478
+            end: Position { line: 1, col: 1 },
1479
+        };
12531480
         let st = super::super::symtab::SymbolTable::new();
12541481
 
1255
-        let left = Box::new(Spanned::new(Expr::IntegerLiteral { text: "1".into(), kind: None }, span));
1256
-        let right = Box::new(Spanned::new(Expr::RealLiteral { text: "2.0".into(), kind: None }, span));
1257
-        let expr = Spanned::new(Expr::BinaryOp { op: BinaryOp::Add, left, right }, span);
1482
+        let left = Box::new(Spanned::new(
1483
+            Expr::IntegerLiteral {
1484
+                text: "1".into(),
1485
+                kind: None,
1486
+            },
1487
+            span,
1488
+        ));
1489
+        let right = Box::new(Spanned::new(
1490
+            Expr::RealLiteral {
1491
+                text: "2.0".into(),
1492
+                kind: None,
1493
+            },
1494
+            span,
1495
+        ));
1496
+        let expr = Spanned::new(
1497
+            Expr::BinaryOp {
1498
+                op: BinaryOp::Add,
1499
+                left,
1500
+                right,
1501
+            },
1502
+            span,
1503
+        );
12581504
         assert_eq!(expr_type(&expr, &st), FortranType::Real { kind: 4 });
12591505
     }
12601506
 
@@ -1262,31 +1508,61 @@ mod tests {
12621508
     fn expr_type_unary_minus() {
12631509
         use crate::ast::expr::{Expr, UnaryOp};
12641510
         use crate::ast::Spanned;
1265
-        use crate::lexer::{Span, Position};
1266
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1511
+        use crate::lexer::{Position, Span};
1512
+        let span = Span {
1513
+            file_id: 0,
1514
+            start: Position { line: 1, col: 1 },
1515
+            end: Position { line: 1, col: 1 },
1516
+        };
12671517
         let st = super::super::symtab::SymbolTable::new();
12681518
 
1269
-        let operand = Box::new(Spanned::new(Expr::RealLiteral { text: "3.14".into(), kind: None }, span));
1270
-        let expr = Spanned::new(Expr::UnaryOp { op: UnaryOp::Minus, operand }, span);
1519
+        let operand = Box::new(Spanned::new(
1520
+            Expr::RealLiteral {
1521
+                text: "3.14".into(),
1522
+                kind: None,
1523
+            },
1524
+            span,
1525
+        ));
1526
+        let expr = Spanned::new(
1527
+            Expr::UnaryOp {
1528
+                op: UnaryOp::Minus,
1529
+                operand,
1530
+            },
1531
+            span,
1532
+        );
12711533
         assert_eq!(expr_type(&expr, &st), FortranType::Real { kind: 4 });
12721534
     }
12731535
 
12741536
     #[test]
12751537
     fn expr_type_intrinsic_call() {
1276
-        use crate::ast::expr::{Expr, Argument, SectionSubscript};
1538
+        use crate::ast::expr::{Argument, Expr, SectionSubscript};
12771539
         use crate::ast::Spanned;
1278
-        use crate::lexer::{Span, Position};
1279
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1540
+        use crate::lexer::{Position, Span};
1541
+        let span = Span {
1542
+            file_id: 0,
1543
+            start: Position { line: 1, col: 1 },
1544
+            end: Position { line: 1, col: 1 },
1545
+        };
12801546
         let st = super::super::symtab::SymbolTable::new();
12811547
 
12821548
         let callee = Box::new(Spanned::new(Expr::Name { name: "abs".into() }, span));
12831549
         let arg = Argument {
12841550
             keyword: None,
12851551
             value: SectionSubscript::Element(Spanned::new(
1286
-                Expr::IntegerLiteral { text: "-5".into(), kind: None }, span
1552
+                Expr::IntegerLiteral {
1553
+                    text: "-5".into(),
1554
+                    kind: None,
1555
+                },
1556
+                span,
12871557
             )),
12881558
         };
1289
-        let expr = Spanned::new(Expr::FunctionCall { callee, args: vec![arg] }, span);
1559
+        let expr = Spanned::new(
1560
+            Expr::FunctionCall {
1561
+                callee,
1562
+                args: vec![arg],
1563
+            },
1564
+            span,
1565
+        );
12901566
         assert_eq!(expr_type(&expr, &st), FortranType::Integer { kind: 4 });
12911567
     }
12921568
 
@@ -1294,22 +1570,36 @@ mod tests {
12941570
     fn expr_type_paren() {
12951571
         use crate::ast::expr::Expr;
12961572
         use crate::ast::Spanned;
1297
-        use crate::lexer::{Span, Position};
1298
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1573
+        use crate::lexer::{Position, Span};
1574
+        let span = Span {
1575
+            file_id: 0,
1576
+            start: Position { line: 1, col: 1 },
1577
+            end: Position { line: 1, col: 1 },
1578
+        };
12991579
         let st = super::super::symtab::SymbolTable::new();
13001580
 
1301
-        let inner = Box::new(Spanned::new(Expr::RealLiteral { text: "1.0".into(), kind: None }, span));
1581
+        let inner = Box::new(Spanned::new(
1582
+            Expr::RealLiteral {
1583
+                text: "1.0".into(),
1584
+                kind: None,
1585
+            },
1586
+            span,
1587
+        ));
13021588
         let expr = Spanned::new(Expr::ParenExpr { inner }, span);
13031589
         assert_eq!(expr_type(&expr, &st), FortranType::Real { kind: 4 });
13041590
     }
13051591
 
13061592
     #[test]
13071593
     fn expr_type_array_element() {
1308
-        use crate::ast::expr::{Expr, Argument, SectionSubscript};
1309
-        use crate::ast::Spanned;
1310
-        use crate::lexer::{Span, Position};
13111594
         use super::super::symtab::*;
1312
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1595
+        use crate::ast::expr::{Argument, Expr, SectionSubscript};
1596
+        use crate::ast::Spanned;
1597
+        use crate::lexer::{Position, Span};
1598
+        let span = Span {
1599
+            file_id: 0,
1600
+            start: Position { line: 1, col: 1 },
1601
+            end: Position { line: 1, col: 1 },
1602
+        };
13131603
 
13141604
         let mut st = SymbolTable::new();
13151605
         st.push_scope(ScopeKind::Program("main".into()));
@@ -1322,51 +1612,88 @@ mod tests {
13221612
             scope: 0,
13231613
             arg_names: vec![],
13241614
             const_value: None,
1325
-        }).unwrap();
1615
+        })
1616
+        .unwrap();
13261617
 
13271618
         let callee = Box::new(Spanned::new(Expr::Name { name: "arr".into() }, span));
13281619
         let arg = Argument {
13291620
             keyword: None,
13301621
             value: SectionSubscript::Element(Spanned::new(
1331
-                Expr::IntegerLiteral { text: "3".into(), kind: None }, span
1622
+                Expr::IntegerLiteral {
1623
+                    text: "3".into(),
1624
+                    kind: None,
1625
+                },
1626
+                span,
13321627
             )),
13331628
         };
1334
-        let expr = Spanned::new(Expr::FunctionCall { callee, args: vec![arg] }, span);
1629
+        let expr = Spanned::new(
1630
+            Expr::FunctionCall {
1631
+                callee,
1632
+                args: vec![arg],
1633
+            },
1634
+            span,
1635
+        );
13351636
         // arr(3) where arr is a variable → array element → real(8)
13361637
         assert_eq!(expr_type(&expr, &st), FortranType::Real { kind: 8 });
13371638
     }
13381639
 
13391640
     #[test]
13401641
     fn expr_type_substring() {
1341
-        use crate::ast::expr::{Expr, Argument, SectionSubscript};
1342
-        use crate::ast::Spanned;
1343
-        use crate::lexer::{Span, Position};
13441642
         use super::super::symtab::*;
1345
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
1643
+        use crate::ast::expr::{Argument, Expr, SectionSubscript};
1644
+        use crate::ast::Spanned;
1645
+        use crate::lexer::{Position, Span};
1646
+        let span = Span {
1647
+            file_id: 0,
1648
+            start: Position { line: 1, col: 1 },
1649
+            end: Position { line: 1, col: 1 },
1650
+        };
13461651
 
13471652
         let mut st = SymbolTable::new();
13481653
         st.push_scope(ScopeKind::Program("main".into()));
13491654
         st.define(Symbol {
13501655
             name: "s".into(),
13511656
             kind: SymbolKind::Variable,
1352
-            type_info: Some(TypeInfo::Character { len: Some(20), kind: None }),
1657
+            type_info: Some(TypeInfo::Character {
1658
+                len: Some(20),
1659
+                kind: None,
1660
+            }),
13531661
             attrs: SymbolAttrs::default(),
13541662
             defined_at: span,
13551663
             scope: 0,
13561664
             arg_names: vec![],
13571665
             const_value: None,
1358
-        }).unwrap();
1666
+        })
1667
+        .unwrap();
13591668
 
13601669
         let callee = Box::new(Spanned::new(Expr::Name { name: "s".into() }, span));
13611670
         let arg = Argument {
13621671
             keyword: None,
13631672
             value: SectionSubscript::Range {
1364
-                start: Some(Spanned::new(Expr::IntegerLiteral { text: "1".into(), kind: None }, span)),
1365
-                end: Some(Spanned::new(Expr::IntegerLiteral { text: "5".into(), kind: None }, span)),
1673
+                start: Some(Spanned::new(
1674
+                    Expr::IntegerLiteral {
1675
+                        text: "1".into(),
1676
+                        kind: None,
1677
+                    },
1678
+                    span,
1679
+                )),
1680
+                end: Some(Spanned::new(
1681
+                    Expr::IntegerLiteral {
1682
+                        text: "5".into(),
1683
+                        kind: None,
1684
+                    },
1685
+                    span,
1686
+                )),
13661687
                 stride: None,
13671688
             },
13681689
         };
1369
-        let expr = Spanned::new(Expr::FunctionCall { callee, args: vec![arg] }, span);
1690
+        let expr = Spanned::new(
1691
+            Expr::FunctionCall {
1692
+                callee,
1693
+                args: vec![arg],
1694
+            },
1695
+            span,
1696
+        );
13701697
         // s(1:5) where s is character variable → substring
13711698
         assert!(expr_type(&expr, &st).is_character());
13721699
     }
@@ -1377,8 +1704,18 @@ mod tests {
13771704
     fn check_args_positional_ok() {
13781705
         use super::super::symtab::Intent;
13791706
         let dummies = vec![
1380
-            DummyArgDesc { name: "a".into(), type_: FortranType::Real { kind: 4 }, intent: Some(Intent::In), optional: false },
1381
-            DummyArgDesc { name: "n".into(), type_: FortranType::Integer { kind: 4 }, intent: Some(Intent::In), optional: false },
1707
+            DummyArgDesc {
1708
+                name: "a".into(),
1709
+                type_: FortranType::Real { kind: 4 },
1710
+                intent: Some(Intent::In),
1711
+                optional: false,
1712
+            },
1713
+            DummyArgDesc {
1714
+                name: "n".into(),
1715
+                type_: FortranType::Integer { kind: 4 },
1716
+                intent: Some(Intent::In),
1717
+                optional: false,
1718
+            },
13821719
         ];
13831720
         let actuals = vec![
13841721
             (None, FortranType::Real { kind: 4 }),
@@ -1391,8 +1728,18 @@ mod tests {
13911728
     fn check_args_keyword_ok() {
13921729
         use super::super::symtab::Intent;
13931730
         let dummies = vec![
1394
-            DummyArgDesc { name: "a".into(), type_: FortranType::Real { kind: 4 }, intent: Some(Intent::In), optional: false },
1395
-            DummyArgDesc { name: "n".into(), type_: FortranType::Integer { kind: 4 }, intent: Some(Intent::In), optional: false },
1731
+            DummyArgDesc {
1732
+                name: "a".into(),
1733
+                type_: FortranType::Real { kind: 4 },
1734
+                intent: Some(Intent::In),
1735
+                optional: false,
1736
+            },
1737
+            DummyArgDesc {
1738
+                name: "n".into(),
1739
+                type_: FortranType::Integer { kind: 4 },
1740
+                intent: Some(Intent::In),
1741
+                optional: false,
1742
+            },
13961743
         ];
13971744
         let actuals = vec![
13981745
             (Some("n".into()), FortranType::Integer { kind: 4 }),
@@ -1404,24 +1751,40 @@ mod tests {
14041751
     #[test]
14051752
     fn check_args_optional_omitted_ok() {
14061753
         let dummies = vec![
1407
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1408
-            DummyArgDesc { name: "verbose".into(), type_: FortranType::default_logical(), intent: None, optional: true },
1409
-        ];
1410
-        let actuals = vec![
1411
-            (None, FortranType::Real { kind: 4 }),
1754
+            DummyArgDesc {
1755
+                name: "x".into(),
1756
+                type_: FortranType::Real { kind: 4 },
1757
+                intent: None,
1758
+                optional: false,
1759
+            },
1760
+            DummyArgDesc {
1761
+                name: "verbose".into(),
1762
+                type_: FortranType::default_logical(),
1763
+                intent: None,
1764
+                optional: true,
1765
+            },
14121766
         ];
1767
+        let actuals = vec![(None, FortranType::Real { kind: 4 })];
14131768
         assert!(check_arguments(&dummies, &actuals).is_empty());
14141769
     }
14151770
 
14161771
     #[test]
14171772
     fn check_args_missing_required() {
14181773
         let dummies = vec![
1419
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1420
-            DummyArgDesc { name: "y".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1421
-        ];
1422
-        let actuals = vec![
1423
-            (None, FortranType::Real { kind: 4 }),
1774
+            DummyArgDesc {
1775
+                name: "x".into(),
1776
+                type_: FortranType::Real { kind: 4 },
1777
+                intent: None,
1778
+                optional: false,
1779
+            },
1780
+            DummyArgDesc {
1781
+                name: "y".into(),
1782
+                type_: FortranType::Real { kind: 4 },
1783
+                intent: None,
1784
+                optional: false,
1785
+            },
14241786
         ];
1787
+        let actuals = vec![(None, FortranType::Real { kind: 4 })];
14251788
         let errs = check_arguments(&dummies, &actuals);
14261789
         assert_eq!(errs.len(), 1);
14271790
         assert!(errs[0].contains("missing required argument 'y'"));
@@ -1429,9 +1792,12 @@ mod tests {
14291792
 
14301793
     #[test]
14311794
     fn check_args_too_many() {
1432
-        let dummies = vec![
1433
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1434
-        ];
1795
+        let dummies = vec![DummyArgDesc {
1796
+            name: "x".into(),
1797
+            type_: FortranType::Real { kind: 4 },
1798
+            intent: None,
1799
+            optional: false,
1800
+        }];
14351801
         let actuals = vec![
14361802
             (None, FortranType::Real { kind: 4 }),
14371803
             (None, FortranType::Real { kind: 4 }),
@@ -1443,12 +1809,13 @@ mod tests {
14431809
 
14441810
     #[test]
14451811
     fn check_args_type_mismatch() {
1446
-        let dummies = vec![
1447
-            DummyArgDesc { name: "x".into(), type_: FortranType::default_logical(), intent: None, optional: false },
1448
-        ];
1449
-        let actuals = vec![
1450
-            (None, FortranType::Integer { kind: 4 }),
1451
-        ];
1812
+        let dummies = vec![DummyArgDesc {
1813
+            name: "x".into(),
1814
+            type_: FortranType::default_logical(),
1815
+            intent: None,
1816
+            optional: false,
1817
+        }];
1818
+        let actuals = vec![(None, FortranType::Integer { kind: 4 })];
14521819
         let errs = check_arguments(&dummies, &actuals);
14531820
         assert_eq!(errs.len(), 1);
14541821
         assert!(errs[0].contains("type mismatch"));
@@ -1456,21 +1823,25 @@ mod tests {
14561823
 
14571824
     #[test]
14581825
     fn check_args_numeric_conversion_allowed() {
1459
-        let dummies = vec![
1460
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 8 }, intent: None, optional: false },
1461
-        ];
1462
-        let actuals = vec![
1463
-            (None, FortranType::Integer { kind: 4 }),
1464
-        ];
1826
+        let dummies = vec![DummyArgDesc {
1827
+            name: "x".into(),
1828
+            type_: FortranType::Real { kind: 8 },
1829
+            intent: None,
1830
+            optional: false,
1831
+        }];
1832
+        let actuals = vec![(None, FortranType::Integer { kind: 4 })];
14651833
         // integer → real conversion allowed
14661834
         assert!(check_arguments(&dummies, &actuals).is_empty());
14671835
     }
14681836
 
14691837
     #[test]
14701838
     fn check_args_duplicate_keyword() {
1471
-        let dummies = vec![
1472
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1473
-        ];
1839
+        let dummies = vec![DummyArgDesc {
1840
+            name: "x".into(),
1841
+            type_: FortranType::Real { kind: 4 },
1842
+            intent: None,
1843
+            optional: false,
1844
+        }];
14741845
         let actuals = vec![
14751846
             (Some("x".into()), FortranType::Real { kind: 4 }),
14761847
             (Some("x".into()), FortranType::Real { kind: 4 }),
@@ -1481,12 +1852,13 @@ mod tests {
14811852
 
14821853
     #[test]
14831854
     fn check_args_unknown_keyword() {
1484
-        let dummies = vec![
1485
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1486
-        ];
1487
-        let actuals = vec![
1488
-            (Some("bogus".into()), FortranType::Real { kind: 4 }),
1489
-        ];
1855
+        let dummies = vec![DummyArgDesc {
1856
+            name: "x".into(),
1857
+            type_: FortranType::Real { kind: 4 },
1858
+            intent: None,
1859
+            optional: false,
1860
+        }];
1861
+        let actuals = vec![(Some("bogus".into()), FortranType::Real { kind: 4 })];
14901862
         let errs = check_arguments(&dummies, &actuals);
14911863
         assert!(errs.iter().any(|e| e.contains("unknown keyword")));
14921864
     }
@@ -1499,43 +1871,77 @@ mod tests {
14991871
             SpecificProc {
15001872
                 name: "swap_int".into(),
15011873
                 dummy_args: vec![
1502
-                    DummyArgDesc { name: "a".into(), type_: FortranType::Integer { kind: 4 }, intent: None, optional: false },
1503
-                    DummyArgDesc { name: "b".into(), type_: FortranType::Integer { kind: 4 }, intent: None, optional: false },
1874
+                    DummyArgDesc {
1875
+                        name: "a".into(),
1876
+                        type_: FortranType::Integer { kind: 4 },
1877
+                        intent: None,
1878
+                        optional: false,
1879
+                    },
1880
+                    DummyArgDesc {
1881
+                        name: "b".into(),
1882
+                        type_: FortranType::Integer { kind: 4 },
1883
+                        intent: None,
1884
+                        optional: false,
1885
+                    },
15041886
                 ],
15051887
                 result_type: FortranType::Void,
15061888
             },
15071889
             SpecificProc {
15081890
                 name: "swap_real".into(),
15091891
                 dummy_args: vec![
1510
-                    DummyArgDesc { name: "a".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1511
-                    DummyArgDesc { name: "b".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1892
+                    DummyArgDesc {
1893
+                        name: "a".into(),
1894
+                        type_: FortranType::Real { kind: 4 },
1895
+                        intent: None,
1896
+                        optional: false,
1897
+                    },
1898
+                    DummyArgDesc {
1899
+                        name: "b".into(),
1900
+                        type_: FortranType::Real { kind: 4 },
1901
+                        intent: None,
1902
+                        optional: false,
1903
+                    },
15121904
                 ],
15131905
                 result_type: FortranType::Void,
15141906
             },
15151907
         ];
15161908
 
15171909
         // integer args → swap_int (index 0)
1518
-        assert_eq!(resolve_generic(&specifics, &[
1519
-            FortranType::Integer { kind: 4 }, FortranType::Integer { kind: 4 }
1520
-        ]).unwrap(), 0);
1910
+        assert_eq!(
1911
+            resolve_generic(
1912
+                &specifics,
1913
+                &[
1914
+                    FortranType::Integer { kind: 4 },
1915
+                    FortranType::Integer { kind: 4 }
1916
+                ]
1917
+            )
1918
+            .unwrap(),
1919
+            0
1920
+        );
15211921
 
15221922
         // real args → swap_real (index 1)
1523
-        assert_eq!(resolve_generic(&specifics, &[
1524
-            FortranType::Real { kind: 4 }, FortranType::Real { kind: 4 }
1525
-        ]).unwrap(), 1);
1923
+        assert_eq!(
1924
+            resolve_generic(
1925
+                &specifics,
1926
+                &[FortranType::Real { kind: 4 }, FortranType::Real { kind: 4 }]
1927
+            )
1928
+            .unwrap(),
1929
+            1
1930
+        );
15261931
     }
15271932
 
15281933
     #[test]
15291934
     fn resolve_generic_no_match() {
1530
-        let specifics = vec![
1531
-            SpecificProc {
1532
-                name: "foo_int".into(),
1533
-                dummy_args: vec![
1534
-                    DummyArgDesc { name: "x".into(), type_: FortranType::Integer { kind: 4 }, intent: None, optional: false },
1535
-                ],
1536
-                result_type: FortranType::Void,
1537
-            },
1538
-        ];
1935
+        let specifics = vec![SpecificProc {
1936
+            name: "foo_int".into(),
1937
+            dummy_args: vec![DummyArgDesc {
1938
+                name: "x".into(),
1939
+                type_: FortranType::Integer { kind: 4 },
1940
+                intent: None,
1941
+                optional: false,
1942
+            }],
1943
+            result_type: FortranType::Void,
1944
+        }];
15391945
         assert!(resolve_generic(&specifics, &[FortranType::Real { kind: 4 }]).is_err());
15401946
     }
15411947
 
@@ -1545,42 +1951,76 @@ mod tests {
15451951
             SpecificProc {
15461952
                 name: "swap_int".into(),
15471953
                 dummy_args: vec![
1548
-                    DummyArgDesc { name: "a".into(), type_: FortranType::Integer { kind: 4 }, intent: None, optional: false },
1549
-                    DummyArgDesc { name: "b".into(), type_: FortranType::Integer { kind: 4 }, intent: None, optional: false },
1954
+                    DummyArgDesc {
1955
+                        name: "a".into(),
1956
+                        type_: FortranType::Integer { kind: 4 },
1957
+                        intent: None,
1958
+                        optional: false,
1959
+                    },
1960
+                    DummyArgDesc {
1961
+                        name: "b".into(),
1962
+                        type_: FortranType::Integer { kind: 4 },
1963
+                        intent: None,
1964
+                        optional: false,
1965
+                    },
15501966
                 ],
15511967
                 result_type: FortranType::Void,
15521968
             },
15531969
             SpecificProc {
15541970
                 name: "swap_real".into(),
15551971
                 dummy_args: vec![
1556
-                    DummyArgDesc { name: "a".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1557
-                    DummyArgDesc { name: "b".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1972
+                    DummyArgDesc {
1973
+                        name: "a".into(),
1974
+                        type_: FortranType::Real { kind: 4 },
1975
+                        intent: None,
1976
+                        optional: false,
1977
+                    },
1978
+                    DummyArgDesc {
1979
+                        name: "b".into(),
1980
+                        type_: FortranType::Real { kind: 4 },
1981
+                        intent: None,
1982
+                        optional: false,
1983
+                    },
15581984
                 ],
15591985
                 result_type: FortranType::Void,
15601986
             },
15611987
         ];
15621988
         // mixed integer + real → no match (exact type required for disambiguation)
1563
-        assert!(resolve_generic(&specifics, &[
1564
-            FortranType::Integer { kind: 4 }, FortranType::Real { kind: 4 }
1565
-        ]).is_err());
1989
+        assert!(resolve_generic(
1990
+            &specifics,
1991
+            &[
1992
+                FortranType::Integer { kind: 4 },
1993
+                FortranType::Real { kind: 4 }
1994
+            ]
1995
+        )
1996
+        .is_err());
15661997
     }
15671998
 
15681999
     #[test]
15692000
     fn resolve_generic_with_optional() {
1570
-        let specifics = vec![
1571
-            SpecificProc {
1572
-                name: "process".into(),
1573
-                dummy_args: vec![
1574
-                    DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1575
-                    DummyArgDesc { name: "mask".into(), type_: FortranType::default_logical(), intent: None, optional: true },
1576
-                ],
1577
-                result_type: FortranType::Void,
1578
-            },
1579
-        ];
2001
+        let specifics = vec![SpecificProc {
2002
+            name: "process".into(),
2003
+            dummy_args: vec![
2004
+                DummyArgDesc {
2005
+                    name: "x".into(),
2006
+                    type_: FortranType::Real { kind: 4 },
2007
+                    intent: None,
2008
+                    optional: false,
2009
+                },
2010
+                DummyArgDesc {
2011
+                    name: "mask".into(),
2012
+                    type_: FortranType::default_logical(),
2013
+                    intent: None,
2014
+                    optional: true,
2015
+                },
2016
+            ],
2017
+            result_type: FortranType::Void,
2018
+        }];
15802019
         // Only required arg supplied — should match
1581
-        assert_eq!(resolve_generic(&specifics, &[
1582
-            FortranType::Real { kind: 4 }
1583
-        ]).unwrap(), 0);
2020
+        assert_eq!(
2021
+            resolve_generic(&specifics, &[FortranType::Real { kind: 4 }]).unwrap(),
2022
+            0
2023
+        );
15842024
     }
15852025
 
15862026
     // ---- Logical result type ----
@@ -1601,7 +2041,8 @@ mod tests {
16012041
         let result = binary_logical_result_type(
16022042
             &FortranType::Logical { kind: 1 },
16032043
             &FortranType::Logical { kind: 8 },
1604
-        ).unwrap();
2044
+        )
2045
+        .unwrap();
16052046
         assert_eq!(result, FortranType::Logical { kind: 8 });
16062047
     }
16072048
 
@@ -1613,7 +2054,8 @@ mod tests {
16132054
         let result = arithmetic_result_type(
16142055
             &FortranType::Real { kind: 8 },
16152056
             &FortranType::Complex { kind: 4 },
1616
-        ).unwrap();
2057
+        )
2058
+        .unwrap();
16172059
         assert_eq!(result, FortranType::Complex { kind: 8 });
16182060
     }
16192061
 
@@ -1623,7 +2065,8 @@ mod tests {
16232065
         let result = arithmetic_result_type(
16242066
             &FortranType::Integer { kind: 8 },
16252067
             &FortranType::Real { kind: 4 },
1626
-        ).unwrap();
2068
+        )
2069
+        .unwrap();
16272070
         assert_eq!(result, FortranType::Real { kind: 4 });
16282071
     }
16292072
 
@@ -1633,7 +2076,8 @@ mod tests {
16332076
         let result = arithmetic_result_type(
16342077
             &FortranType::Integer { kind: 8 },
16352078
             &FortranType::Complex { kind: 4 },
1636
-        ).unwrap();
2079
+        )
2080
+        .unwrap();
16372081
         assert_eq!(result, FortranType::Complex { kind: 4 });
16382082
     }
16392083
 
@@ -1643,7 +2087,8 @@ mod tests {
16432087
         let result = arithmetic_result_type(
16442088
             &FortranType::Real { kind: 4 },
16452089
             &FortranType::Integer { kind: 8 },
1646
-        ).unwrap();
2090
+        )
2091
+        .unwrap();
16472092
         assert_eq!(result, FortranType::Real { kind: 4 });
16482093
     }
16492094
 
@@ -1652,15 +2097,27 @@ mod tests {
16522097
     #[test]
16532098
     fn positional_after_keyword_rejected() {
16542099
         let dummies = vec![
1655
-            DummyArgDesc { name: "a".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
1656
-            DummyArgDesc { name: "b".into(), type_: FortranType::Real { kind: 4 }, intent: None, optional: false },
2100
+            DummyArgDesc {
2101
+                name: "a".into(),
2102
+                type_: FortranType::Real { kind: 4 },
2103
+                intent: None,
2104
+                optional: false,
2105
+            },
2106
+            DummyArgDesc {
2107
+                name: "b".into(),
2108
+                type_: FortranType::Real { kind: 4 },
2109
+                intent: None,
2110
+                optional: false,
2111
+            },
16572112
         ];
16582113
         let actuals = vec![
16592114
             (Some("a".into()), FortranType::Real { kind: 4 }),
16602115
             (None, FortranType::Real { kind: 4 }), // positional after keyword
16612116
         ];
16622117
         let errs = check_arguments(&dummies, &actuals);
1663
-        assert!(errs.iter().any(|e| e.contains("positional argument after keyword")));
2118
+        assert!(errs
2119
+            .iter()
2120
+            .any(|e| e.contains("positional argument after keyword")));
16642121
     }
16652122
 
16662123
     // ---- Audit fix: M5 — intent(out/inout) rejects numeric conversion ----
@@ -1668,12 +2125,13 @@ mod tests {
16682125
     #[test]
16692126
     fn intent_inout_rejects_numeric_conversion() {
16702127
         use super::super::symtab::Intent;
1671
-        let dummies = vec![
1672
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 8 }, intent: Some(Intent::InOut), optional: false },
1673
-        ];
1674
-        let actuals = vec![
1675
-            (None, FortranType::Integer { kind: 4 }),
1676
-        ];
2128
+        let dummies = vec![DummyArgDesc {
2129
+            name: "x".into(),
2130
+            type_: FortranType::Real { kind: 8 },
2131
+            intent: Some(Intent::InOut),
2132
+            optional: false,
2133
+        }];
2134
+        let actuals = vec![(None, FortranType::Integer { kind: 4 })];
16772135
         let errs = check_arguments(&dummies, &actuals);
16782136
         assert!(!errs.is_empty());
16792137
         assert!(errs[0].contains("intent(out/inout)"));
@@ -1682,12 +2140,13 @@ mod tests {
16822140
     #[test]
16832141
     fn intent_in_allows_numeric_conversion() {
16842142
         use super::super::symtab::Intent;
1685
-        let dummies = vec![
1686
-            DummyArgDesc { name: "x".into(), type_: FortranType::Real { kind: 8 }, intent: Some(Intent::In), optional: false },
1687
-        ];
1688
-        let actuals = vec![
1689
-            (None, FortranType::Integer { kind: 4 }),
1690
-        ];
2143
+        let dummies = vec![DummyArgDesc {
2144
+            name: "x".into(),
2145
+            type_: FortranType::Real { kind: 8 },
2146
+            intent: Some(Intent::In),
2147
+            optional: false,
2148
+        }];
2149
+        let actuals = vec![(None, FortranType::Integer { kind: 4 })];
16912150
         assert!(check_arguments(&dummies, &actuals).is_empty());
16922151
     }
16932152
 
@@ -1728,7 +2187,8 @@ mod tests {
17282187
         assert!(needs_conversion(
17292188
             &FortranType::Complex { kind: 4 },
17302189
             &FortranType::Integer { kind: 4 },
1731
-        ).is_none());
2190
+        )
2191
+        .is_none());
17322192
     }
17332193
 
17342194
     #[test]
@@ -1736,7 +2196,8 @@ mod tests {
17362196
         assert!(needs_conversion(
17372197
             &FortranType::Complex { kind: 4 },
17382198
             &FortranType::Real { kind: 4 },
1739
-        ).is_none());
2199
+        )
2200
+        .is_none());
17402201
     }
17412202
 
17422203
     #[test]
@@ -1744,7 +2205,8 @@ mod tests {
17442205
         let conv = needs_conversion(
17452206
             &FortranType::Integer { kind: 4 },
17462207
             &FortranType::Complex { kind: 4 },
1747
-        ).unwrap();
2208
+        )
2209
+        .unwrap();
17482210
         assert_eq!(conv, FortranType::Complex { kind: 4 });
17492211
     }
17502212
 
@@ -1753,9 +2215,16 @@ mod tests {
17532215
     #[test]
17542216
     fn concat_mismatched_kind_returns_none() {
17552217
         assert!(concat_result_type(
1756
-            &FortranType::Character { kind: 1, len: CharLen::Known(5) },
1757
-            &FortranType::Character { kind: 4, len: CharLen::Known(5) },
1758
-        ).is_none());
2218
+            &FortranType::Character {
2219
+                kind: 1,
2220
+                len: CharLen::Known(5)
2221
+            },
2222
+            &FortranType::Character {
2223
+                kind: 4,
2224
+                len: CharLen::Known(5)
2225
+            },
2226
+        )
2227
+        .is_none());
17592228
     }
17602229
 
17612230
     // ---- New intrinsics ----
@@ -1768,9 +2237,13 @@ mod tests {
17682237
 
17692238
     #[test]
17702239
     fn intrinsic_c_associated() {
1771
-        let result = intrinsic_result_type("c_associated", &[
1772
-            FortranType::Derived { name: "c_ptr".into() }
1773
-        ]).unwrap();
2240
+        let result = intrinsic_result_type(
2241
+            "c_associated",
2242
+            &[FortranType::Derived {
2243
+                name: "c_ptr".into(),
2244
+            }],
2245
+        )
2246
+        .unwrap();
17742247
         assert_eq!(result, FortranType::default_logical());
17752248
     }
17762249
 
@@ -1782,11 +2255,15 @@ mod tests {
17822255
 
17832256
     #[test]
17842257
     fn intrinsic_merge() {
1785
-        let result = intrinsic_result_type("merge", &[
1786
-            FortranType::Integer { kind: 4 },
1787
-            FortranType::Integer { kind: 4 },
1788
-            FortranType::default_logical(),
1789
-        ]).unwrap();
2258
+        let result = intrinsic_result_type(
2259
+            "merge",
2260
+            &[
2261
+                FortranType::Integer { kind: 4 },
2262
+                FortranType::Integer { kind: 4 },
2263
+                FortranType::default_logical(),
2264
+            ],
2265
+        )
2266
+        .unwrap();
17902267
         assert_eq!(result, FortranType::Integer { kind: 4 });
17912268
     }
17922269
 }
src/sema/validate.rsmodified
1701 lines changed — click to load
@@ -4,12 +4,12 @@
44
 //! constraints, label validation, and standard conformance. Runs after
55
 //! symbol resolution (resolve.rs) and type checking (types.rs).
66
 
7
-use crate::ast::unit::*;
8
-use crate::ast::stmt::*;
7
+use super::symtab::*;
8
+use crate::ast::decl::{Attribute, Decl, TypeAttr, TypeSpec};
99
 use crate::ast::expr::Expr;
10
-use crate::ast::decl::{Decl, Attribute, TypeAttr, TypeSpec};
10
+use crate::ast::stmt::*;
11
+use crate::ast::unit::*;
1112
 use crate::lexer::Span;
12
-use super::symtab::*;
1313
 use std::cell::RefCell;
1414
 
1515
 /// Fortran standard level for --std= conformance checking.
@@ -60,7 +60,11 @@ impl std::fmt::Display for Diagnostic {
6060
             DiagKind::Error => "error",
6161
             DiagKind::Warning => "warning",
6262
         };
63
-        write!(f, "{}:{}: {}: {}", self.span.start.line, self.span.start.col, label, self.msg)
63
+        write!(
64
+            f,
65
+            "{}:{}: {}: {}",
66
+            self.span.start.line, self.span.start.col, label, self.msg
67
+        )
6468
     }
6569
 }
6670
 
@@ -128,7 +132,10 @@ impl<'a> Ctx<'a> {
128132
     fn require_std(&mut self, span: Span, min: FortranStandard, feature: &str) {
129133
         if let Some(selected) = self.std {
130134
             if selected < min {
131
-                self.error(span, format!("{} requires --std={:?} or later", feature, min));
135
+                self.error(
136
+                    span,
137
+                    format!("{} requires --std={:?} or later", feature, min),
138
+                );
132139
             }
133140
         }
134141
     }
@@ -145,11 +152,19 @@ impl<'a> Ctx<'a> {
145152
     }
146153
 
147154
     fn error(&mut self, span: Span, msg: impl Into<String>) {
148
-        self.diags.push(Diagnostic { span, kind: DiagKind::Error, msg: msg.into() });
155
+        self.diags.push(Diagnostic {
156
+            span,
157
+            kind: DiagKind::Error,
158
+            msg: msg.into(),
159
+        });
149160
     }
150161
 
151162
     fn warning(&mut self, span: Span, msg: impl Into<String>) {
152
-        self.diags.push(Diagnostic { span, kind: DiagKind::Warning, msg: msg.into() });
163
+        self.diags.push(Diagnostic {
164
+            span,
165
+            kind: DiagKind::Warning,
166
+            msg: msg.into(),
167
+        });
153168
     }
154169
 }
155170
 
@@ -190,14 +205,7 @@ pub fn validate_file_with_layouts(
190205
     std: Option<FortranStandard>,
191206
     type_layouts: &crate::sema::type_layout::TypeLayoutRegistry,
192207
 ) -> Vec<Diagnostic> {
193
-    validate_file_with_layouts_and_warning_groups(
194
-        units,
195
-        st,
196
-        std,
197
-        type_layouts,
198
-        false,
199
-        false,
200
-    )
208
+    validate_file_with_layouts_and_warning_groups(units, st, std, type_layouts, false, false)
201209
 }
202210
 
203211
 pub fn validate_file_with_layouts_and_warning_groups(
@@ -208,13 +216,7 @@ pub fn validate_file_with_layouts_and_warning_groups(
208216
     warn_pedantic: bool,
209217
     warn_deprecated: bool,
210218
 ) -> Vec<Diagnostic> {
211
-    let mut ctx = Ctx::new_with_layouts(
212
-        st,
213
-        std,
214
-        type_layouts,
215
-        warn_pedantic,
216
-        warn_deprecated,
217
-    );
219
+    let mut ctx = Ctx::new_with_layouts(st, std, type_layouts, warn_pedantic, warn_deprecated);
218220
     for unit in units {
219221
         validate_unit(&mut ctx, unit);
220222
     }
@@ -231,10 +233,7 @@ fn decl_attrs_contain(attrs: &[Attribute], needle: Attribute) -> bool {
231233
     attrs.iter().any(|attr| *attr == needle)
232234
 }
233235
 
234
-fn is_deferred_char_pointer_component(
235
-    type_spec: &TypeSpec,
236
-    attrs: &[Attribute],
237
-) -> bool {
236
+fn is_deferred_char_pointer_component(type_spec: &TypeSpec, attrs: &[Attribute]) -> bool {
238237
     decl_attrs_contain(attrs, Attribute::Pointer)
239238
         && matches!(
240239
             type_spec,
@@ -340,15 +339,15 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
340339
             }
341340
             for implicit_stmt in implicit {
342341
                 if matches!(implicit_stmt.node, Decl::ImplicitNone { .. }) {
343
-                    ctx.require_std(
344
-                        implicit_stmt.span,
345
-                        FortranStandard::F90,
346
-                        "IMPLICIT NONE",
347
-                    );
342
+                    ctx.require_std(implicit_stmt.span, FortranStandard::F90, "IMPLICIT NONE");
348343
                 }
349344
             }
350345
             if !contains.is_empty() {
351
-                ctx.require_std(unit.span, FortranStandard::F90, "CONTAINS/internal procedures");
346
+                ctx.require_std(
347
+                    unit.span,
348
+                    FortranStandard::F90,
349
+                    "CONTAINS/internal procedures",
350
+                );
352351
             }
353352
             validate_decls(ctx, decls);
354353
             check_implicit_none(ctx, body, decls);
@@ -361,7 +360,9 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
361360
         ProgramUnit::Module {
362361
             uses,
363362
             implicit,
364
-            decls, contains, ..
363
+            decls,
364
+            contains,
365
+            ..
365366
         } => {
366367
             ctx.require_std(unit.span, FortranStandard::F90, "MODULE");
367368
             for use_stmt in uses {
@@ -369,11 +370,7 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
369370
             }
370371
             for implicit_stmt in implicit {
371372
                 if matches!(implicit_stmt.node, Decl::ImplicitNone { .. }) {
372
-                    ctx.require_std(
373
-                        implicit_stmt.span,
374
-                        FortranStandard::F90,
375
-                        "IMPLICIT NONE",
376
-                    );
373
+                    ctx.require_std(implicit_stmt.span, FortranStandard::F90, "IMPLICIT NONE");
377374
                 }
378375
             }
379376
             validate_decls(ctx, decls);
@@ -422,15 +419,15 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
422419
             }
423420
             for implicit_stmt in implicit {
424421
                 if matches!(implicit_stmt.node, Decl::ImplicitNone { .. }) {
425
-                    ctx.require_std(
426
-                        implicit_stmt.span,
427
-                        FortranStandard::F90,
428
-                        "IMPLICIT NONE",
429
-                    );
422
+                    ctx.require_std(implicit_stmt.span, FortranStandard::F90, "IMPLICIT NONE");
430423
                 }
431424
             }
432425
             if !contains.is_empty() {
433
-                ctx.require_std(unit.span, FortranStandard::F90, "CONTAINS/internal procedures");
426
+                ctx.require_std(
427
+                    unit.span,
428
+                    FortranStandard::F90,
429
+                    "CONTAINS/internal procedures",
430
+                );
434431
             }
435432
             validate_decls(ctx, decls);
436433
             check_implicit_none(ctx, body, decls);
@@ -483,15 +480,15 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
483480
             }
484481
             for implicit_stmt in implicit {
485482
                 if matches!(implicit_stmt.node, Decl::ImplicitNone { .. }) {
486
-                    ctx.require_std(
487
-                        implicit_stmt.span,
488
-                        FortranStandard::F90,
489
-                        "IMPLICIT NONE",
490
-                    );
483
+                    ctx.require_std(implicit_stmt.span, FortranStandard::F90, "IMPLICIT NONE");
491484
                 }
492485
             }
493486
             if !contains.is_empty() {
494
-                ctx.require_std(unit.span, FortranStandard::F90, "CONTAINS/internal procedures");
487
+                ctx.require_std(
488
+                    unit.span,
489
+                    FortranStandard::F90,
490
+                    "CONTAINS/internal procedures",
491
+                );
495492
             }
496493
             validate_decls(ctx, decls);
497494
             check_implicit_none(ctx, body, decls);
@@ -505,7 +502,9 @@ fn validate_unit(ctx: &mut Ctx, unit: &SpannedUnit) {
505502
         }
506503
         ProgramUnit::Submodule {
507504
             uses,
508
-            decls, contains, ..
505
+            decls,
506
+            contains,
507
+            ..
509508
         } => {
510509
             ctx.require_std(unit.span, FortranStandard::F2008, "SUBMODULE");
511510
             for use_stmt in uses {
@@ -701,7 +700,9 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
701700
         Stmt::Assignment { target, value } => {
702701
             validate_assignment_target(ctx, target, stmt.span);
703702
             reject_pure_nonlocal_definition(ctx, target, stmt.span, "assignment");
704
-            if ctx.in_pure { check_pure_expr_calls(ctx, value); }
703
+            if ctx.in_pure {
704
+                check_pure_expr_calls(ctx, value);
705
+            }
705706
         }
706707
         Stmt::PointerAssignment { target, value, .. } => {
707708
             validate_pointer_assignment(ctx, target, value, stmt.span);
@@ -728,10 +729,17 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
728729
         }
729730
 
730731
         // ---- I/O in pure ----
731
-        Stmt::Write { .. } | Stmt::Read { .. } | Stmt::Print { .. } |
732
-        Stmt::Open { .. } | Stmt::Close { .. } | Stmt::Inquire { .. } |
733
-        Stmt::Rewind { .. } | Stmt::Backspace { .. } | Stmt::Endfile { .. } |
734
-        Stmt::Flush { .. } | Stmt::Wait { .. } => {
732
+        Stmt::Write { .. }
733
+        | Stmt::Read { .. }
734
+        | Stmt::Print { .. }
735
+        | Stmt::Open { .. }
736
+        | Stmt::Close { .. }
737
+        | Stmt::Inquire { .. }
738
+        | Stmt::Rewind { .. }
739
+        | Stmt::Backspace { .. }
740
+        | Stmt::Endfile { .. }
741
+        | Stmt::Flush { .. }
742
+        | Stmt::Wait { .. } => {
735743
             if ctx.in_pure {
736744
                 ctx.error(stmt.span, "I/O statement not allowed in pure procedure");
737745
             }
@@ -775,7 +783,12 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
775783
         }
776784
 
777785
         // ---- Control flow — recurse into bodies ----
778
-        Stmt::IfConstruct { then_body, else_ifs, else_body, .. } => {
786
+        Stmt::IfConstruct {
787
+            then_body,
788
+            else_ifs,
789
+            else_body,
790
+            ..
791
+        } => {
779792
             validate_stmts(ctx, then_body);
780793
             for (_, body) in else_ifs {
781794
                 validate_stmts(ctx, body);
@@ -813,7 +826,14 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
813826
             ctx.require_std(stmt.span, FortranStandard::F95, "FORALL statement");
814827
             validate_stmt(ctx, inner);
815828
         }
816
-        Stmt::Block { uses, ifaces, implicit, decls, body, .. } => {
829
+        Stmt::Block {
830
+            uses,
831
+            ifaces,
832
+            implicit,
833
+            decls,
834
+            body,
835
+            ..
836
+        } => {
817837
             ctx.require_std(stmt.span, FortranStandard::F2008, "BLOCK construct");
818838
             validate_decls(ctx, uses);
819839
             validate_decls(ctx, implicit);
@@ -847,9 +867,10 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
847867
                 if let Some(ref name) = extract_base_name(item) {
848868
                     let is_pointer = ctx.lookup(name).map(|s| s.attrs.pointer).unwrap_or(true);
849869
                     if !is_pointer {
850
-                        ctx.error(item.span, format!(
851
-                            "NULLIFY target '{}' must have pointer attribute", name
852
-                        ));
870
+                        ctx.error(
871
+                            item.span,
872
+                            format!("NULLIFY target '{}' must have pointer attribute", name),
873
+                        );
853874
                     }
854875
                 }
855876
             }
@@ -871,17 +892,22 @@ fn validate_stmt(ctx: &mut Ctx, stmt: &SpannedStmt) {
871892
 /// variable's intent/parameter status applies to all parts.
872893
 fn validate_assignment_target(ctx: &mut Ctx, target: &crate::ast::expr::SpannedExpr, span: Span) {
873894
     if let Some(name) = extract_base_name(target) {
874
-        let (is_intent_in, is_parameter, is_pointer) = ctx.lookup(&name)
875
-            .map(|sym| (
876
-                matches!(sym.attrs.intent, Some(Intent::In)),
877
-                sym.attrs.parameter,
878
-                sym.attrs.pointer,
879
-            ))
895
+        let (is_intent_in, is_parameter, is_pointer) = ctx
896
+            .lookup(&name)
897
+            .map(|sym| {
898
+                (
899
+                    matches!(sym.attrs.intent, Some(Intent::In)),
900
+                    sym.attrs.parameter,
901
+                    sym.attrs.pointer,
902
+                )
903
+            })
880904
             .unwrap_or((false, false, false));
881
-        let writes_through_pointer_target =
882
-            is_pointer && !matches!(target.node, Expr::Name { .. });
905
+        let writes_through_pointer_target = is_pointer && !matches!(target.node, Expr::Name { .. });
883906
         if is_intent_in && !writes_through_pointer_target {
884
-            ctx.error(span, format!("cannot assign to intent(in) variable '{}'", name));
907
+            ctx.error(
908
+                span,
909
+                format!("cannot assign to intent(in) variable '{}'", name),
910
+            );
885911
         }
886912
         if is_parameter {
887913
             ctx.error(span, format!("cannot assign to named constant '{}'", name));
@@ -903,16 +929,25 @@ fn validate_pointer_assignment(
903929
     if expr_selects_component(target) {
904930
         if let Some(leaf) = leaf_field_layout(ctx, target) {
905931
             if !leaf.field.pointer {
906
-                ctx.error(span, format!(
907
-                    "pointer assignment target component '{}' must have pointer attribute",
908
-                    leaf.field.name
909
-                ));
932
+                ctx.error(
933
+                    span,
934
+                    format!(
935
+                        "pointer assignment target component '{}' must have pointer attribute",
936
+                        leaf.field.name
937
+                    ),
938
+                );
910939
             }
911940
         }
912941
     } else if let Some(name) = extract_base_name(target) {
913942
         let is_pointer = ctx.lookup(&name).map(|s| s.attrs.pointer).unwrap_or(true);
914943
         if !is_pointer {
915
-            ctx.error(span, format!("pointer assignment target '{}' must have pointer attribute", name));
944
+            ctx.error(
945
+                span,
946
+                format!(
947
+                    "pointer assignment target '{}' must have pointer attribute",
948
+                    name
949
+                ),
950
+            );
916951
         }
917952
     }
918953
 
@@ -956,9 +991,18 @@ fn validate_pointer_assignment(
956991
                 return;
957992
             }
958993
         }
959
-        let ok = ctx.lookup(&name).map(|s| s.attrs.target || s.attrs.pointer).unwrap_or(true);
994
+        let ok = ctx
995
+            .lookup(&name)
996
+            .map(|s| s.attrs.target || s.attrs.pointer)
997
+            .unwrap_or(true);
960998
         if !ok {
961
-            ctx.error(span, format!("pointer assignment source '{}' must have target or pointer attribute", name));
999
+            ctx.error(
1000
+                span,
1001
+                format!(
1002
+                    "pointer assignment source '{}' must have target or pointer attribute",
1003
+                    name
1004
+                ),
1005
+            );
9621006
         }
9631007
     }
9641008
 }
@@ -976,24 +1020,32 @@ fn validate_allocatable_item(ctx: &mut Ctx, item: &crate::ast::expr::SpannedExpr
9761020
     if expr_selects_component(item) {
9771021
         if let Some(leaf) = leaf_field_layout(ctx, item) {
9781022
             if !leaf.field.allocatable && !leaf.field.pointer {
979
-                ctx.error(item.span, format!(
1023
+                ctx.error(
1024
+                    item.span,
1025
+                    format!(
9801026
                     "only allocatable or pointer components can appear in {}, but '{}' is neither",
9811027
                     stmt_name.to_uppercase(), leaf.field.name
982
-                ));
1028
+                ),
1029
+                );
9831030
             }
9841031
         }
9851032
         return;
9861033
     }
9871034
     let base_name = extract_base_name(item);
9881035
     if let Some(ref name) = base_name {
989
-        let ok = ctx.lookup(name)
1036
+        let ok = ctx
1037
+            .lookup(name)
9901038
             .map(|s| s.attrs.allocatable || s.attrs.pointer)
9911039
             .unwrap_or(true); // unknown symbol — skip
9921040
         if !ok {
993
-            ctx.error(item.span, format!(
994
-                "only allocatable or pointer variables can appear in {}, but '{}' is neither",
995
-                stmt_name.to_uppercase(), name
996
-            ));
1041
+            ctx.error(
1042
+                item.span,
1043
+                format!(
1044
+                    "only allocatable or pointer variables can appear in {}, but '{}' is neither",
1045
+                    stmt_name.to_uppercase(),
1046
+                    name
1047
+                ),
1048
+            );
9971049
         }
9981050
     }
9991051
 }
@@ -1050,7 +1102,9 @@ fn leaf_field_layout<'a>(
10501102
         }
10511103
     };
10521104
     chain.reverse();
1053
-    if chain.is_empty() { return None; }
1105
+    if chain.is_empty() {
1106
+        return None;
1107
+    }
10541108
     // Resolve the base variable's derived type via the symbol table.
10551109
     let sym = ctx.lookup(base_name)?;
10561110
     let base_type = match sym.type_info.as_ref()? {
@@ -1069,8 +1123,12 @@ fn leaf_field_layout<'a>(
10691123
         // so the leaf check can honour inherited target-ness.
10701124
         let is_terminal = i + 1 == chain.len();
10711125
         if !is_terminal {
1072
-            if field.target { ancestor_is_target = true; }
1073
-            if field.allocatable { ancestor_is_allocatable = true; }
1126
+            if field.target {
1127
+                ancestor_is_target = true;
1128
+            }
1129
+            if field.allocatable {
1130
+                ancestor_is_allocatable = true;
1131
+            }
10741132
         }
10751133
         leaf = Some(field);
10761134
         match &field.type_info {
@@ -1123,8 +1181,12 @@ fn validate_pure_call(ctx: &mut Ctx, callee: &crate::ast::expr::SpannedExpr, spa
11231181
     // symbol that is NOT marked pure/elemental/intrinsic, reject.
11241182
     // Unknown callees (external without an interface) are left
11251183
     // alone — the programmer's responsibility per F2018 §15.4.
1126
-    let Some(name) = extract_base_name(callee) else { return; };
1127
-    let Some(sym) = ctx.lookup(&name) else { return; };
1184
+    let Some(name) = extract_base_name(callee) else {
1185
+        return;
1186
+    };
1187
+    let Some(sym) = ctx.lookup(&name) else {
1188
+        return;
1189
+    };
11281190
     match sym.kind {
11291191
         SymbolKind::Function | SymbolKind::Subroutine => {
11301192
             if !sym.attrs.pure && !sym.attrs.elemental && !sym.attrs.intrinsic {
@@ -1138,7 +1200,7 @@ fn validate_pure_call(ctx: &mut Ctx, callee: &crate::ast::expr::SpannedExpr, spa
11381200
             }
11391201
         }
11401202
         SymbolKind::IntrinsicProc => {} // always OK
1141
-        _ => {} // external / unknown — can't check
1203
+        _ => {}                         // external / unknown — can't check
11421204
     }
11431205
 }
11441206
 
@@ -1183,12 +1245,19 @@ fn reject_pure_nonlocal_definition(
11831245
     if !ctx.in_pure {
11841246
         return;
11851247
     }
1186
-    let Some(name) = extract_base_name(target) else { return; };
1187
-    let Some(sym) = ctx.lookup(&name) else { return; };
1248
+    let Some(name) = extract_base_name(target) else {
1249
+        return;
1250
+    };
1251
+    let Some(sym) = ctx.lookup(&name) else {
1252
+        return;
1253
+    };
11881254
     // Only variables and COMMON blocks can be "defined"; function
11891255
     // names get definition semantics too but those are the pure
11901256
     // function's own result variable (always local).
1191
-    if !matches!(sym.kind, SymbolKind::Variable | SymbolKind::Parameter | SymbolKind::CommonBlock) {
1257
+    if !matches!(
1258
+        sym.kind,
1259
+        SymbolKind::Variable | SymbolKind::Parameter | SymbolKind::CommonBlock
1260
+    ) {
11921261
         return;
11931262
     }
11941263
     if symbol_is_non_local_to_procedure(ctx.st, sym, ctx.scope_id) {
@@ -1212,7 +1281,11 @@ fn validate_call_site_intent(
12121281
     span: Span,
12131282
 ) {
12141283
     // Look up the callee to find its dummy argument intents.
1215
-    let callee_name = if let Expr::Name { name } = &callee.node { name.clone() } else { return; };
1284
+    let callee_name = if let Expr::Name { name } = &callee.node {
1285
+        name.clone()
1286
+    } else {
1287
+        return;
1288
+    };
12161289
 
12171290
     // For each actual argument, check if it's an lvalue when the dummy requires out/inout.
12181291
     // We can only check this if the callee's dummy arg info is in the symbol table.
@@ -1223,15 +1296,22 @@ fn validate_call_site_intent(
12231296
             _ => continue,
12241297
         };
12251298
         // Check if actual is a literal (not an lvalue).
1226
-        let is_literal = matches!(actual.node,
1227
-            Expr::IntegerLiteral { .. } | Expr::RealLiteral { .. } |
1228
-            Expr::StringLiteral { .. } | Expr::LogicalLiteral { .. } |
1229
-            Expr::ComplexLiteral { .. }
1299
+        let is_literal = matches!(
1300
+            actual.node,
1301
+            Expr::IntegerLiteral { .. }
1302
+                | Expr::RealLiteral { .. }
1303
+                | Expr::StringLiteral { .. }
1304
+                | Expr::LogicalLiteral { .. }
1305
+                | Expr::ComplexLiteral { .. }
12301306
         );
12311307
         // Check if actual is a named constant (parameter).
12321308
         let is_parameter = if let Some(name) = extract_base_name(actual) {
1233
-            ctx.lookup(&name).map(|s| s.attrs.parameter).unwrap_or(false)
1234
-        } else { false };
1309
+            ctx.lookup(&name)
1310
+                .map(|s| s.attrs.parameter)
1311
+                .unwrap_or(false)
1312
+        } else {
1313
+            false
1314
+        };
12351315
 
12361316
         if is_literal || is_parameter {
12371317
             // We can't tell without the callee's interface whether this arg is
@@ -1256,17 +1336,24 @@ fn validate_elemental_args(
12561336
     for arg in args {
12571337
         if let DummyArg::Name(arg_name) = arg {
12581338
             for decl in decls {
1259
-                if let Decl::TypeDecl { attrs, entities, .. } = &decl.node {
1339
+                if let Decl::TypeDecl {
1340
+                    attrs, entities, ..
1341
+                } = &decl.node
1342
+                {
12601343
                     for entity in entities {
12611344
                         if entity.name.eq_ignore_ascii_case(arg_name) {
12621345
                             // Check for dimension attribute or explicit array spec on entity.
1263
-                            let has_dimension = attrs.iter().any(|a| matches!(a, Attribute::Dimension(_)));
1346
+                            let has_dimension =
1347
+                                attrs.iter().any(|a| matches!(a, Attribute::Dimension(_)));
12641348
                             let has_entity_dims = entity.array_spec.is_some();
12651349
                             if has_dimension || has_entity_dims {
1266
-                                ctx.error(span, format!(
1267
-                                    "elemental procedure argument '{}' must be scalar",
1268
-                                    arg_name
1269
-                                ));
1350
+                                ctx.error(
1351
+                                    span,
1352
+                                    format!(
1353
+                                        "elemental procedure argument '{}' must be scalar",
1354
+                                        arg_name
1355
+                                    ),
1356
+                                );
12701357
                             }
12711358
                         }
12721359
                     }
@@ -1288,9 +1375,16 @@ fn register_label(ctx: &mut Ctx, label: u64, span: Span) {
12881375
 /// At the end of a scope, verify all GOTO labels have targets.
12891376
 fn validate_label_consistency(ctx: &mut Ctx, _scope_span: Span) {
12901377
     // Collect errors first to avoid borrow conflict.
1291
-    let errors: Vec<(Span, String)> = ctx.labels_referenced.iter()
1378
+    let errors: Vec<(Span, String)> = ctx
1379
+        .labels_referenced
1380
+        .iter()
12921381
         .filter(|(label, _)| !ctx.labels_defined.contains(label))
1293
-        .map(|(label, span)| (*span, format!("GOTO target label {} not defined in this scope", label)))
1382
+        .map(|(label, span)| {
1383
+            (
1384
+                *span,
1385
+                format!("GOTO target label {} not defined in this scope", label),
1386
+            )
1387
+        })
12941388
         .collect();
12951389
     for (span, msg) in errors {
12961390
         ctx.error(span, msg);
@@ -1321,34 +1415,46 @@ fn validate_operator_interface(
13211415
                 match &sub.node {
13221416
                     ProgramUnit::Function { args, .. } => {
13231417
                         if is_assignment {
1324
-                            ctx.error(sub.span, format!(
1418
+                            ctx.error(
1419
+                                sub.span,
1420
+                                format!(
13251421
                                 "ASSIGNMENT({}) interface must contain subroutines, not functions",
13261422
                                 "="
1327
-                            ));
1423
+                            ),
1424
+                            );
13281425
                             continue;
13291426
                         }
13301427
                         // Operator functions: unary = 1 arg, binary = 2 args.
13311428
                         let nargs = args.len();
13321429
                         if !(1..=2).contains(&nargs) {
1333
-                            ctx.error(sub.span, format!(
1430
+                            ctx.error(
1431
+                                sub.span,
1432
+                                format!(
13341433
                                 "operator interface function must have 1 or 2 arguments, got {}",
13351434
                                 nargs
1336
-                            ));
1435
+                            ),
1436
+                            );
13371437
                         }
13381438
                         // All arguments must be intent(in) — checked by looking at decls.
13391439
                         // Deferred: would need to walk the function's decls to check intent.
13401440
                     }
13411441
                     ProgramUnit::Subroutine { args, .. } => {
13421442
                         if !is_assignment {
1343
-                            ctx.error(sub.span, "operator interface must contain functions, not subroutines");
1443
+                            ctx.error(
1444
+                                sub.span,
1445
+                                "operator interface must contain functions, not subroutines",
1446
+                            );
13441447
                             continue;
13451448
                         }
13461449
                         // Assignment subroutines must have exactly 2 arguments.
13471450
                         if args.len() != 2 {
1348
-                            ctx.error(sub.span, format!(
1451
+                            ctx.error(
1452
+                                sub.span,
1453
+                                format!(
13491454
                                 "ASSIGNMENT(=) interface subroutine must have 2 arguments, got {}",
13501455
                                 args.len()
1351
-                            ));
1456
+                            ),
1457
+                            );
13521458
                         }
13531459
                     }
13541460
                     _ => {
@@ -1380,10 +1486,13 @@ fn validate_derived_type(
13801486
         // Deferred procedures only allowed in abstract types.
13811487
         let is_deferred = tbp.attrs.iter().any(|a| a.eq_ignore_ascii_case("deferred"));
13821488
         if is_deferred && !is_abstract {
1383
-            ctx.error(span, format!(
1384
-                "type-bound procedure '{}' is DEFERRED but type '{}' is not ABSTRACT",
1385
-                tbp.name, name
1386
-            ));
1489
+            ctx.error(
1490
+                span,
1491
+                format!(
1492
+                    "type-bound procedure '{}' is DEFERRED but type '{}' is not ABSTRACT",
1493
+                    tbp.name, name
1494
+                ),
1495
+            );
13871496
         }
13881497
 
13891498
         // PASS and NOPASS are mutually exclusive.
@@ -1393,18 +1502,24 @@ fn validate_derived_type(
13931502
         });
13941503
         let has_nopass = tbp.attrs.iter().any(|a| a.eq_ignore_ascii_case("nopass"));
13951504
         if has_pass && has_nopass {
1396
-            ctx.error(span, format!(
1397
-                "type-bound procedure '{}' cannot have both PASS and NOPASS",
1398
-                tbp.name
1399
-            ));
1505
+            ctx.error(
1506
+                span,
1507
+                format!(
1508
+                    "type-bound procedure '{}' cannot have both PASS and NOPASS",
1509
+                    tbp.name
1510
+                ),
1511
+            );
14001512
         }
14011513
 
14021514
         // Deferred procedures must have an interface (binding).
14031515
         if is_deferred && tbp.binding.is_none() {
1404
-            ctx.error(span, format!(
1405
-                "DEFERRED type-bound procedure '{}' must specify an interface",
1406
-                tbp.name
1407
-            ));
1516
+            ctx.error(
1517
+                span,
1518
+                format!(
1519
+                    "DEFERRED type-bound procedure '{}' must specify an interface",
1520
+                    tbp.name
1521
+                ),
1522
+            );
14081523
         }
14091524
     }
14101525
 }
@@ -1438,8 +1553,14 @@ fn extract_base_name(expr: &crate::ast::expr::SpannedExpr) -> Option<String> {
14381553
 
14391554
 /// Check that all variable references in a statement list are declared
14401555
 /// when IMPLICIT NONE is active in the current scope.
1441
-fn check_implicit_none(ctx: &mut Ctx, stmts: &[SpannedStmt], decls: &[crate::ast::decl::SpannedDecl]) {
1442
-    if !ctx.st.is_implicit_none(ctx.scope_id) { return; }
1556
+fn check_implicit_none(
1557
+    ctx: &mut Ctx,
1558
+    stmts: &[SpannedStmt],
1559
+    decls: &[crate::ast::decl::SpannedDecl],
1560
+) {
1561
+    if !ctx.st.is_implicit_none(ctx.scope_id) {
1562
+        return;
1563
+    }
14431564
 
14441565
     // Collect declared names in this scope (from declarations).
14451566
     let mut declared: std::collections::HashSet<String> = std::collections::HashSet::new();
@@ -1451,7 +1572,10 @@ fn check_implicit_none(ctx: &mut Ctx, stmts: &[SpannedStmt], decls: &[crate::ast
14511572
     // should have them via resolve. We also check decls for
14521573
     // EXTERNAL statements.
14531574
     for decl in decls {
1454
-        if let Decl::TypeDecl { attrs, entities, .. } = &decl.node {
1575
+        if let Decl::TypeDecl {
1576
+            attrs, entities, ..
1577
+        } = &decl.node
1578
+        {
14551579
             if attrs.iter().any(|a| matches!(a, Attribute::External)) {
14561580
                 for e in entities {
14571581
                     declared.insert(e.name.to_lowercase());
@@ -1463,8 +1587,7 @@ fn check_implicit_none(ctx: &mut Ctx, stmts: &[SpannedStmt], decls: &[crate::ast
14631587
     let mut undeclared = Vec::new();
14641588
     let mut resolution_cache: std::collections::HashMap<String, bool> =
14651589
         std::collections::HashMap::new();
1466
-    let outer_implicit_letters: std::collections::HashSet<char> =
1467
-        std::collections::HashSet::new();
1590
+    let outer_implicit_letters: std::collections::HashSet<char> = std::collections::HashSet::new();
14681591
     for stmt in stmts {
14691592
         walk_stmt_for_undeclared(
14701593
             ctx.st,
@@ -1482,9 +1605,13 @@ fn check_implicit_none(ctx: &mut Ctx, stmts: &[SpannedStmt], decls: &[crate::ast
14821605
     for (name, span) in &undeclared {
14831606
         let key = name.to_lowercase();
14841607
         if reported.insert(key) {
1485
-            ctx.error(*span, format!(
1486
-                "variable '{}' used but not declared (IMPLICIT NONE is active)", name
1487
-            ));
1608
+            ctx.error(
1609
+                *span,
1610
+                format!(
1611
+                    "variable '{}' used but not declared (IMPLICIT NONE is active)",
1612
+                    name
1613
+                ),
1614
+            );
14881615
         }
14891616
     }
14901617
 }
@@ -1524,8 +1651,7 @@ fn extend_declared_names_from_ifaces(
15241651
         for body in bodies {
15251652
             match body {
15261653
                 InterfaceBody::Subprogram(sub) => match &sub.node {
1527
-                    ProgramUnit::Function { name, .. }
1528
-                    | ProgramUnit::Subroutine { name, .. } => {
1654
+                    ProgramUnit::Function { name, .. } | ProgramUnit::Subroutine { name, .. } => {
15291655
                         declared.insert(name.to_lowercase());
15301656
                     }
15311657
                     _ => {}
@@ -1577,41 +1703,80 @@ fn walk_stmt_for_undeclared(
15771703
     }
15781704
     match &stmt.node {
15791705
         Stmt::Assignment { target, value } => {
1580
-            chk!(target); chk!(value);
1706
+            chk!(target);
1707
+            chk!(value);
15811708
         }
15821709
         Stmt::PointerAssignment { target, value, .. } => {
1583
-            chk!(target); chk!(value);
1710
+            chk!(target);
1711
+            chk!(value);
15841712
         }
15851713
         Stmt::Print { items, .. } => {
1586
-            for item in items { chk!(item); }
1714
+            for item in items {
1715
+                chk!(item);
1716
+            }
15871717
         }
1588
-        Stmt::Write { items, controls, .. } => {
1589
-            for item in items { chk!(item); }
1590
-            for ctrl in controls { chk!(&ctrl.value); }
1718
+        Stmt::Write {
1719
+            items, controls, ..
1720
+        } => {
1721
+            for item in items {
1722
+                chk!(item);
1723
+            }
1724
+            for ctrl in controls {
1725
+                chk!(&ctrl.value);
1726
+            }
15911727
         }
1592
-        Stmt::Read { items, controls, .. } => {
1593
-            for item in items { chk!(item); }
1594
-            for ctrl in controls { chk!(&ctrl.value); }
1728
+        Stmt::Read {
1729
+            items, controls, ..
1730
+        } => {
1731
+            for item in items {
1732
+                chk!(item);
1733
+            }
1734
+            for ctrl in controls {
1735
+                chk!(&ctrl.value);
1736
+            }
15951737
         }
1596
-        Stmt::IfConstruct { condition, then_body, else_ifs, else_body, .. } => {
1738
+        Stmt::IfConstruct {
1739
+            condition,
1740
+            then_body,
1741
+            else_ifs,
1742
+            else_body,
1743
+            ..
1744
+        } => {
15971745
             chk!(condition);
1598
-            for s in then_body { recurse!(s); }
1746
+            for s in then_body {
1747
+                recurse!(s);
1748
+            }
15991749
             for (cond, body) in else_ifs {
16001750
                 chk!(cond);
1601
-                for s in body { recurse!(s); }
1751
+                for s in body {
1752
+                    recurse!(s);
1753
+                }
16021754
             }
16031755
             if let Some(body) = else_body {
1604
-                for s in body { recurse!(s); }
1756
+                for s in body {
1757
+                    recurse!(s);
1758
+                }
16051759
             }
16061760
         }
16071761
         Stmt::IfStmt { condition, action } => {
1608
-            chk!(condition); recurse!(action);
1762
+            chk!(condition);
1763
+            recurse!(action);
16091764
         }
1610
-        Stmt::DoLoop { body, .. } | Stmt::DoWhile { body, .. } |
1611
-        Stmt::DoConcurrent { body, .. } => {
1612
-            for s in body { recurse!(s); }
1765
+        Stmt::DoLoop { body, .. }
1766
+        | Stmt::DoWhile { body, .. }
1767
+        | Stmt::DoConcurrent { body, .. } => {
1768
+            for s in body {
1769
+                recurse!(s);
1770
+            }
16131771
         }
1614
-        Stmt::Block { uses, ifaces, implicit, decls, body, .. } => {
1772
+        Stmt::Block {
1773
+            uses,
1774
+            ifaces,
1775
+            implicit,
1776
+            decls,
1777
+            body,
1778
+            ..
1779
+        } => {
16151780
             // F2018 §11.1.4: a BLOCK construct establishes its own
16161781
             // scope with an independent implicit-typing environment.
16171782
             // Layer the block's declared names AND any IMPLICIT
@@ -1672,10 +1837,14 @@ fn walk_stmt_for_undeclared(
16721837
                 );
16731838
             }
16741839
         }
1675
-        Stmt::SelectCase { selector, cases, .. } => {
1840
+        Stmt::SelectCase {
1841
+            selector, cases, ..
1842
+        } => {
16761843
             chk!(selector);
16771844
             for case in cases {
1678
-                for s in &case.body { recurse!(s); }
1845
+                for s in &case.body {
1846
+                    recurse!(s);
1847
+                }
16791848
             }
16801849
         }
16811850
         Stmt::Call { args, .. } => {
@@ -1685,13 +1854,26 @@ fn walk_stmt_for_undeclared(
16851854
                 }
16861855
             }
16871856
         }
1688
-        Stmt::Labeled { stmt: inner, .. } => { recurse!(inner); }
1689
-        Stmt::WhereConstruct { mask, body, elsewhere, .. } => {
1857
+        Stmt::Labeled { stmt: inner, .. } => {
1858
+            recurse!(inner);
1859
+        }
1860
+        Stmt::WhereConstruct {
1861
+            mask,
1862
+            body,
1863
+            elsewhere,
1864
+            ..
1865
+        } => {
16901866
             chk!(mask);
1691
-            for s in body { recurse!(s); }
1867
+            for s in body {
1868
+                recurse!(s);
1869
+            }
16921870
             for (m, b) in elsewhere {
1693
-                if let Some(m) = m { chk!(m); }
1694
-                for s in b { recurse!(s); }
1871
+                if let Some(m) = m {
1872
+                    chk!(m);
1873
+                }
1874
+                for s in b {
1875
+                    recurse!(s);
1876
+                }
16951877
             }
16961878
         }
16971879
         _ => {}
@@ -1707,7 +1889,13 @@ fn block_use_imported_names(
17071889
 
17081890
     let mut imported = std::collections::HashSet::new();
17091891
     for use_decl in uses {
1710
-        let crate::ast::decl::Decl::UseStmt { module, renames, only, .. } = &use_decl.node else {
1892
+        let crate::ast::decl::Decl::UseStmt {
1893
+            module,
1894
+            renames,
1895
+            only,
1896
+            ..
1897
+        } = &use_decl.node
1898
+        else {
17111899
             continue;
17121900
         };
17131901
         if let Some(only_items) = only {
@@ -1752,9 +1940,15 @@ fn check_expr_names(
17521940
         Expr::Name { name } => {
17531941
             let key = name.to_lowercase();
17541942
             // Skip format specifier * (appears in WRITE(*, *) / READ(*, *)).
1755
-            if key == "*" { return; }
1756
-            if declared.contains(&key) { return; }
1757
-            if is_intrinsic_name(&key) { return; }
1943
+            if key == "*" {
1944
+                return;
1945
+            }
1946
+            if declared.contains(&key) {
1947
+                return;
1948
+            }
1949
+            if is_intrinsic_name(&key) {
1950
+                return;
1951
+            }
17581952
             // F2018 §11.1.4: a BLOCK-scoped IMPLICIT statement gives
17591953
             // names whose first letter is in the covered range an
17601954
             // implicit type, even if the enclosing scope is
@@ -1862,7 +2056,8 @@ fn check_expr_names(
18622056
 }
18632057
 
18642058
 pub fn is_intrinsic_name(name: &str) -> bool {
1865
-    matches!(name,
2059
+    matches!(
2060
+        name,
18662061
         "abs" | "iabs" | "dabs" | "cabs" | "acos" | "asin" | "atan" | "atan2" |
18672062
         "cos" | "sin" | "tan" | "exp" | "log" | "log10" | "sqrt" | "dsqrt" |
18682063
         "mod" | "modulo" | "max" | "min" | "sign" | "dim" |
@@ -1906,12 +2101,14 @@ mod tests {
19062101
         let tokens = Lexer::tokenize(src, 0).unwrap();
19072102
         let mut parser = Parser::new(&tokens);
19082103
         let units = parser.parse_file().unwrap();
1909
-        let rr = resolve::resolve_file(&units, &[]).unwrap(); let st = rr.st;
2104
+        let rr = resolve::resolve_file(&units, &[]).unwrap();
2105
+        let st = rr.st;
19102106
         validate_file(&units, &st)
19112107
     }
19122108
 
19132109
     fn errors_from(src: &str) -> Vec<String> {
1914
-        validate_source(src).iter()
2110
+        validate_source(src)
2111
+            .iter()
19152112
             .filter(|d| d.kind == DiagKind::Error)
19162113
             .map(|d| d.msg.clone())
19172114
             .collect()
@@ -1921,7 +2118,8 @@ mod tests {
19212118
         let tokens = Lexer::tokenize(src, 0).unwrap();
19222119
         let mut parser = Parser::new(&tokens);
19232120
         let units = parser.parse_file().unwrap();
1924
-        let rr = resolve::resolve_file(&units, &[]).unwrap(); let st = rr.st;
2121
+        let rr = resolve::resolve_file(&units, &[]).unwrap();
2122
+        let st = rr.st;
19252123
         validate_file_with_std(&units, &st, Some(std))
19262124
             .iter()
19272125
             .filter(|d| d.kind == DiagKind::Error)
@@ -1933,29 +2131,34 @@ mod tests {
19332131
 
19342132
     #[test]
19352133
     fn assign_to_intent_in_errors() {
1936
-        let errs = errors_from("\
2134
+        let errs = errors_from(
2135
+            "\
19372136
 subroutine foo(x)
19382137
   real, intent(in) :: x
19392138
   x = 1.0
19402139
 end subroutine
1941
-");
2140
+",
2141
+        );
19422142
         assert!(errs.iter().any(|e| e.contains("intent(in)")));
19432143
     }
19442144
 
19452145
     #[test]
19462146
     fn assign_to_intent_inout_ok() {
1947
-        let errs = errors_from("\
2147
+        let errs = errors_from(
2148
+            "\
19482149
 subroutine foo(x)
19492150
   real, intent(inout) :: x
19502151
   x = 1.0
19512152
 end subroutine
1952
-");
2153
+",
2154
+        );
19532155
         assert!(errs.is_empty());
19542156
     }
19552157
 
19562158
     #[test]
19572159
     fn assign_through_intent_in_pointer_target_ok() {
1958
-        let errs = errors_from("\
2160
+        let errs = errors_from(
2161
+            "\
19592162
 module m
19602163
   type :: t
19612164
     integer :: x
@@ -1966,19 +2169,22 @@ contains
19662169
     p%x = 1
19672170
   end subroutine
19682171
 end module
1969
-");
2172
+",
2173
+        );
19702174
         assert!(!errs.iter().any(|e| e.contains("intent(in)")), "{:?}", errs);
19712175
     }
19722176
 
19732177
     #[test]
19742178
     fn assign_to_parameter_errors() {
1975
-        let errs = errors_from("\
2179
+        let errs = errors_from(
2180
+            "\
19762181
 program test
19772182
   implicit none
19782183
   integer, parameter :: n = 10
19792184
   n = 20
19802185
 end program
1981
-");
2186
+",
2187
+        );
19822188
         assert!(errs.iter().any(|e| e.contains("named constant")));
19832189
     }
19842190
 
@@ -1986,88 +2192,106 @@ end program
19862192
 
19872193
     #[test]
19882194
     fn allocate_non_allocatable_errors() {
1989
-        let errs = errors_from("\
2195
+        let errs = errors_from(
2196
+            "\
19902197
 program test
19912198
   implicit none
19922199
   real :: x(10)
19932200
   allocate(x(20))
19942201
 end program
1995
-");
2202
+",
2203
+        );
19962204
         assert!(errs.iter().any(|e| e.contains("allocatable or pointer")));
19972205
     }
19982206
 
19992207
     #[test]
20002208
     fn allocate_allocatable_ok() {
2001
-        let errs = errors_from("\
2209
+        let errs = errors_from(
2210
+            "\
20022211
 program test
20032212
   implicit none
20042213
   real, allocatable :: x(:)
20052214
   allocate(x(10))
20062215
 end program
2007
-");
2216
+",
2217
+        );
20082218
         assert!(errs.is_empty());
20092219
     }
20102220
 
20112221
     #[test]
20122222
     fn allocatable_and_pointer_forbidden() {
2013
-        let errs = errors_from("\
2223
+        let errs = errors_from(
2224
+            "\
20142225
 program test
20152226
   implicit none
20162227
   real, allocatable, pointer :: x
20172228
 end program
2018
-");
2019
-        assert!(errs.iter().any(|e| e.contains("both allocatable and pointer")));
2229
+",
2230
+        );
2231
+        assert!(errs
2232
+            .iter()
2233
+            .any(|e| e.contains("both allocatable and pointer")));
20202234
     }
20212235
 
20222236
     #[test]
20232237
     fn parameter_allocatable_forbidden() {
2024
-        let errs = errors_from("\
2238
+        let errs = errors_from(
2239
+            "\
20252240
 program test
20262241
   implicit none
20272242
   integer, parameter, allocatable :: x = 10
20282243
 end program
2029
-");
2030
-        assert!(errs.iter().any(|e| e.contains("parameter") && e.contains("allocatable")));
2244
+",
2245
+        );
2246
+        assert!(errs
2247
+            .iter()
2248
+            .any(|e| e.contains("parameter") && e.contains("allocatable")));
20312249
     }
20322250
 
20332251
     // ---- Pointer assignment ----
20342252
 
20352253
     #[test]
20362254
     fn pointer_assignment_non_pointer_errors() {
2037
-        let errs = errors_from("\
2255
+        let errs = errors_from(
2256
+            "\
20382257
 program test
20392258
   implicit none
20402259
   real :: x
20412260
   real, target :: y
20422261
   x => y
20432262
 end program
2044
-");
2263
+",
2264
+        );
20452265
         assert!(errs.iter().any(|e| e.contains("pointer attribute")));
20462266
     }
20472267
 
20482268
     #[test]
20492269
     fn pointer_assignment_non_target_errors() {
2050
-        let errs = errors_from("\
2270
+        let errs = errors_from(
2271
+            "\
20512272
 program test
20522273
   implicit none
20532274
   real, pointer :: p
20542275
   real :: x
20552276
   p => x
20562277
 end program
2057
-");
2278
+",
2279
+        );
20582280
         assert!(errs.iter().any(|e| e.contains("target or pointer")));
20592281
     }
20602282
 
20612283
     #[test]
20622284
     fn pointer_assignment_ok() {
2063
-        let errs = errors_from("\
2285
+        let errs = errors_from(
2286
+            "\
20642287
 program test
20652288
   implicit none
20662289
   real, pointer :: p
20672290
   real, target :: x
20682291
   p => x
20692292
 end program
2070
-");
2293
+",
2294
+        );
20712295
         assert!(errs.is_empty());
20722296
     }
20732297
 
@@ -2075,54 +2299,67 @@ end program
20752299
 
20762300
     #[test]
20772301
     fn io_in_pure_errors() {
2078
-        let errs = errors_from("\
2302
+        let errs = errors_from(
2303
+            "\
20792304
 pure subroutine foo(x)
20802305
   real, intent(in) :: x
20812306
   print *, x
20822307
 end subroutine
2083
-");
2308
+",
2309
+        );
20842310
         assert!(errs.iter().any(|e| e.contains("I/O") && e.contains("pure")));
20852311
     }
20862312
 
20872313
     #[test]
20882314
     fn stop_in_pure_errors() {
2089
-        let errs = errors_from("\
2315
+        let errs = errors_from(
2316
+            "\
20902317
 pure function bar(x) result(y)
20912318
   real, intent(in) :: x
20922319
   real :: y
20932320
   y = x
20942321
   stop
20952322
 end function
2096
-");
2097
-        assert!(errs.iter().any(|e| e.contains("STOP") && e.contains("pure")));
2323
+",
2324
+        );
2325
+        assert!(errs
2326
+            .iter()
2327
+            .any(|e| e.contains("STOP") && e.contains("pure")));
20982328
     }
20992329
 
21002330
     #[test]
21012331
     fn save_in_pure_errors() {
2102
-        let errs = errors_from("\
2332
+        let errs = errors_from(
2333
+            "\
21032334
 pure subroutine foo(x)
21042335
   real, intent(in) :: x
21052336
   real, save :: counter
21062337
 end subroutine
2107
-");
2108
-        assert!(errs.iter().any(|e| e.contains("SAVE") && e.contains("pure")));
2338
+",
2339
+        );
2340
+        assert!(errs
2341
+            .iter()
2342
+            .any(|e| e.contains("SAVE") && e.contains("pure")));
21092343
     }
21102344
 
21112345
     #[test]
21122346
     fn pure_without_violations_ok() {
2113
-        let errs = errors_from("\
2347
+        let errs = errors_from(
2348
+            "\
21142349
 pure function square(x) result(y)
21152350
   real, intent(in) :: x
21162351
   real :: y
21172352
   y = x * x
21182353
 end function
2119
-");
2354
+",
2355
+        );
21202356
         assert!(errs.is_empty());
21212357
     }
21222358
 
21232359
     #[test]
21242360
     fn pure_write_to_module_variable_errors() {
2125
-        let errs = errors_from("\
2361
+        let errs = errors_from(
2362
+            "\
21262363
 module m
21272364
   integer :: counter = 0
21282365
 contains
@@ -2131,9 +2368,12 @@ contains
21312368
     r = counter
21322369
   end function
21332370
 end module
2134
-");
2371
+",
2372
+        );
21352373
         assert!(
2136
-            errs.iter().any(|e| e.contains("counter") && e.contains("pure") && e.contains("host or use association")),
2374
+            errs.iter().any(|e| e.contains("counter")
2375
+                && e.contains("pure")
2376
+                && e.contains("host or use association")),
21372377
             "expected pure+module-write error, got {:?}",
21382378
             errs,
21392379
         );
@@ -2144,7 +2384,8 @@ end module
21442384
         // F2018 15.7 permits a pure procedure to *reference* a
21452385
         // variable accessed by use association; only definition
21462386
         // is forbidden.  reads_counter is a legal pure function.
2147
-        let errs = errors_from("\
2387
+        let errs = errors_from(
2388
+            "\
21482389
 module m
21492390
   integer :: counter = 0
21502391
 contains
@@ -2152,13 +2393,19 @@ contains
21522393
     r = counter
21532394
   end function
21542395
 end module
2155
-");
2156
-        assert!(errs.is_empty(), "pure read of module variable should be legal, got {:?}", errs);
2396
+",
2397
+        );
2398
+        assert!(
2399
+            errs.is_empty(),
2400
+            "pure read of module variable should be legal, got {:?}",
2401
+            errs
2402
+        );
21572403
     }
21582404
 
21592405
     #[test]
21602406
     fn pure_write_to_host_variable_errors() {
2161
-        let errs = errors_from("\
2407
+        let errs = errors_from(
2408
+            "\
21622409
 program p
21632410
   integer :: host_var
21642411
   host_var = 0
@@ -2168,9 +2415,12 @@ contains
21682415
     host_var = 42
21692416
   end subroutine
21702417
 end program
2171
-");
2418
+",
2419
+        );
21722420
         assert!(
2173
-            errs.iter().any(|e| e.contains("host_var") && e.contains("pure") && e.contains("host or use association")),
2421
+            errs.iter().any(|e| e.contains("host_var")
2422
+                && e.contains("pure")
2423
+                && e.contains("host or use association")),
21742424
             "expected pure+host-write error, got {:?}",
21752425
             errs,
21762426
         );
@@ -2178,7 +2428,8 @@ end program
21782428
 
21792429
     #[test]
21802430
     fn pure_pointer_reassoc_of_module_pointer_errors() {
2181
-        let errs = errors_from("\
2431
+        let errs = errors_from(
2432
+            "\
21822433
 module m
21832434
   integer, pointer :: module_p
21842435
 contains
@@ -2187,9 +2438,12 @@ contains
21872438
     module_p => t
21882439
   end subroutine
21892440
 end module
2190
-");
2441
+",
2442
+        );
21912443
         assert!(
2192
-            errs.iter().any(|e| e.contains("module_p") && e.contains("pure") && e.contains("pointer assignment")),
2444
+            errs.iter().any(|e| e.contains("module_p")
2445
+                && e.contains("pure")
2446
+                && e.contains("pointer assignment")),
21932447
             "expected pure+module-pointer error, got {:?}",
21942448
             errs,
21952449
         );
@@ -2199,7 +2453,8 @@ end module
21992453
     fn pure_local_pointer_reassoc_ok() {
22002454
         // Associating a LOCAL pointer with a module TARGET is
22012455
         // legal — `q => counter` does not modify `counter`.
2202
-        let errs = errors_from("\
2456
+        let errs = errors_from(
2457
+            "\
22032458
 module m
22042459
   integer, target :: counter = 0
22052460
 contains
@@ -2209,42 +2464,57 @@ contains
22092464
     r = 0
22102465
   end function
22112466
 end module
2212
-");
2213
-        assert!(errs.is_empty(), "pure local pointer reassoc should be legal, got {:?}", errs);
2467
+",
2468
+        );
2469
+        assert!(
2470
+            errs.is_empty(),
2471
+            "pure local pointer reassoc should be legal, got {:?}",
2472
+            errs
2473
+        );
22142474
     }
22152475
 
22162476
     #[test]
22172477
     fn pure_intent_out_dummy_ok() {
2218
-        let errs = errors_from("\
2478
+        let errs = errors_from(
2479
+            "\
22192480
 pure subroutine zero_it(x)
22202481
   integer, intent(out) :: x
22212482
   x = 0
22222483
 end subroutine
2223
-");
2224
-        assert!(errs.is_empty(), "pure write to intent(out) dummy should be legal, got {:?}", errs);
2484
+",
2485
+        );
2486
+        assert!(
2487
+            errs.is_empty(),
2488
+            "pure write to intent(out) dummy should be legal, got {:?}",
2489
+            errs
2490
+        );
22252491
     }
22262492
 
22272493
     // ---- Deferred length character ----
22282494
 
22292495
     #[test]
22302496
     fn deferred_len_without_allocatable_errors() {
2231
-        let errs = errors_from("\
2497
+        let errs = errors_from(
2498
+            "\
22322499
 program test
22332500
   implicit none
22342501
   character(len=:) :: s
22352502
 end program
2236
-");
2503
+",
2504
+        );
22372505
         assert!(errs.iter().any(|e| e.contains("deferred-length")));
22382506
     }
22392507
 
22402508
     #[test]
22412509
     fn deferred_len_with_allocatable_ok() {
2242
-        let errs = errors_from("\
2510
+        let errs = errors_from(
2511
+            "\
22432512
 program test
22442513
   implicit none
22452514
   character(len=:), allocatable :: s
22462515
 end program
2247
-");
2516
+",
2517
+        );
22482518
         assert!(errs.is_empty());
22492519
     }
22502520
 
@@ -2292,10 +2562,14 @@ end program
22922562
 
22932563
     #[test]
22942564
     fn duplicate_label_detected() {
2295
-        use crate::lexer::{Span, Position};
2565
+        use crate::lexer::{Position, Span};
22962566
         let st = SymbolTable::new();
22972567
         let mut ctx = Ctx::new(&st, None, false, false);
2298
-        let span = Span { file_id: 0, start: Position { line: 1, col: 1 }, end: Position { line: 1, col: 1 } };
2568
+        let span = Span {
2569
+            file_id: 0,
2570
+            start: Position { line: 1, col: 1 },
2571
+            end: Position { line: 1, col: 1 },
2572
+        };
22992573
 
23002574
         register_label(&mut ctx, 10, span);
23012575
         register_label(&mut ctx, 10, span); // duplicate
@@ -2306,7 +2580,8 @@ end program
23062580
 
23072581
     #[test]
23082582
     fn clean_program_no_errors() {
2309
-        let errs = errors_from("\
2583
+        let errs = errors_from(
2584
+            "\
23102585
 program test
23112586
   implicit none
23122587
   integer :: i, n
@@ -2316,13 +2591,15 @@ program test
23162591
     x = real(i) * 2.0
23172592
   end do
23182593
 end program
2319
-");
2594
+",
2595
+        );
23202596
         assert!(errs.is_empty(), "unexpected errors: {:?}", errs);
23212597
     }
23222598
 
23232599
     #[test]
23242600
     fn module_with_subroutine_no_errors() {
2325
-        let errs = errors_from("\
2601
+        let errs = errors_from(
2602
+            "\
23262603
 module mymod
23272604
   implicit none
23282605
   integer :: shared
@@ -2332,13 +2609,15 @@ contains
23322609
     shared = val
23332610
   end subroutine
23342611
 end module
2335
-");
2612
+",
2613
+        );
23362614
         assert!(errs.is_empty(), "unexpected errors: {:?}", errs);
23372615
     }
23382616
 
23392617
     #[test]
23402618
     fn module_parameter_visible_in_contained_subroutine() {
2341
-        let errs = errors_from("\
2619
+        let errs = errors_from(
2620
+            "\
23422621
 module m
23432622
   use iso_c_binding, only: c_int
23442623
   implicit none
@@ -2351,7 +2630,8 @@ contains
23512630
     print *, color_red
23522631
   end subroutine
23532632
 end module
2354
-");
2633
+",
2634
+        );
23552635
         assert!(errs.is_empty(), "unexpected errors: {:?}", errs);
23562636
     }
23572637
 
@@ -2363,65 +2643,79 @@ end module
23632643
     #[test]
23642644
     fn operator_interface_subroutine_errors() {
23652645
         // Parse a top-level interface block with operator name.
2366
-        let errs = errors_from("\
2646
+        let errs = errors_from(
2647
+            "\
23672648
 interface operator(+)
23682649
   subroutine bad_add(a, b)
23692650
     integer, intent(in) :: a, b
23702651
   end subroutine
23712652
 end interface
2372
-");
2373
-        assert!(errs.iter().any(|e| e.contains("functions, not subroutines")));
2653
+",
2654
+        );
2655
+        assert!(errs
2656
+            .iter()
2657
+            .any(|e| e.contains("functions, not subroutines")));
23742658
     }
23752659
 
23762660
     #[test]
23772661
     fn operator_interface_wrong_arg_count() {
2378
-        let errs = errors_from("\
2662
+        let errs = errors_from(
2663
+            "\
23792664
 interface operator(+)
23802665
   function add3(a, b, c) result(r)
23812666
     integer, intent(in) :: a, b, c
23822667
     integer :: r
23832668
   end function
23842669
 end interface
2385
-");
2670
+",
2671
+        );
23862672
         assert!(errs.iter().any(|e| e.contains("1 or 2 arguments")));
23872673
     }
23882674
 
23892675
     #[test]
23902676
     fn operator_interface_valid_binary() {
2391
-        let errs = errors_from("\
2677
+        let errs = errors_from(
2678
+            "\
23922679
 interface operator(+)
23932680
   function add_vec(a, b) result(c)
23942681
     integer, intent(in) :: a, b
23952682
     integer :: c
23962683
   end function
23972684
 end interface
2398
-");
2685
+",
2686
+        );
23992687
         assert!(errs.is_empty(), "unexpected errors: {:?}", errs);
24002688
     }
24012689
 
24022690
     #[test]
24032691
     fn assignment_interface_function_errors() {
2404
-        let errs = errors_from("\
2692
+        let errs = errors_from(
2693
+            "\
24052694
 interface assignment(=)
24062695
   function bad_assign(a, b) result(c)
24072696
     integer, intent(in) :: a, b
24082697
     integer :: c
24092698
   end function
24102699
 end interface
2411
-");
2412
-        assert!(errs.iter().any(|e| e.contains("subroutines, not functions")));
2700
+",
2701
+        );
2702
+        assert!(errs
2703
+            .iter()
2704
+            .any(|e| e.contains("subroutines, not functions")));
24132705
     }
24142706
 
24152707
     #[test]
24162708
     fn assignment_interface_wrong_arg_count() {
2417
-        let errs = errors_from("\
2709
+        let errs = errors_from(
2710
+            "\
24182711
 interface assignment(=)
24192712
   subroutine bad_assign(a, b, c)
24202713
     integer, intent(inout) :: a
24212714
     integer, intent(in) :: b, c
24222715
   end subroutine
24232716
 end interface
2424
-");
2717
+",
2718
+        );
24252719
         assert!(errs.iter().any(|e| e.contains("2 arguments")));
24262720
     }
24272721
 
@@ -2429,7 +2723,8 @@ end interface
24292723
 
24302724
     #[test]
24312725
     fn deferred_in_non_abstract_errors() {
2432
-        let errs = errors_from("\
2726
+        let errs = errors_from(
2727
+            "\
24332728
 module m
24342729
   implicit none
24352730
   type :: shape
@@ -2437,13 +2732,17 @@ module m
24372732
     procedure, deferred :: area
24382733
   end type
24392734
 end module
2440
-");
2441
-        assert!(errs.iter().any(|e| e.contains("DEFERRED") && e.contains("not ABSTRACT")));
2735
+",
2736
+        );
2737
+        assert!(errs
2738
+            .iter()
2739
+            .any(|e| e.contains("DEFERRED") && e.contains("not ABSTRACT")));
24422740
     }
24432741
 
24442742
     #[test]
24452743
     fn deferred_in_abstract_ok() {
2446
-        let errs = errors_from("\
2744
+        let errs = errors_from(
2745
+            "\
24472746
 module m
24482747
   implicit none
24492748
   type, abstract :: shape
@@ -2451,7 +2750,8 @@ module m
24512750
     procedure, deferred :: area
24522751
   end type
24532752
 end module
2454
-");
2753
+",
2754
+        );
24552755
         // No error for deferred in abstract type (the "must specify interface"
24562756
         // error is expected since our parser stores binding as None for simple
24572757
         // deferred procedures — that's a parser representation issue).
@@ -2460,7 +2760,8 @@ end module
24602760
 
24612761
     #[test]
24622762
     fn pass_and_nopass_together_errors() {
2463
-        let errs = errors_from("\
2763
+        let errs = errors_from(
2764
+            "\
24642765
 module m
24652766
   implicit none
24662767
   type :: thing
@@ -2468,7 +2769,8 @@ module m
24682769
     procedure, pass, nopass :: method
24692770
   end type
24702771
 end module
2471
-");
2772
+",
2773
+        );
24722774
         assert!(errs.iter().any(|e| e.contains("both PASS and NOPASS")));
24732775
     }
24742776
 
@@ -2476,57 +2778,76 @@ end module
24762778
 
24772779
     #[test]
24782780
     fn do_concurrent_requires_f2008() {
2479
-        let errs = errors_with_std("\
2781
+        let errs = errors_with_std(
2782
+            "\
24802783
 program test
24812784
   implicit none
24822785
   integer :: i
24832786
   do concurrent (i = 1:10)
24842787
   end do
24852788
 end program
2486
-", FortranStandard::F95);
2487
-        assert!(errs.iter().any(|e| e.contains("DO CONCURRENT") && e.contains("F2008")));
2789
+",
2790
+            FortranStandard::F95,
2791
+        );
2792
+        assert!(errs
2793
+            .iter()
2794
+            .any(|e| e.contains("DO CONCURRENT") && e.contains("F2008")));
24882795
     }
24892796
 
24902797
     #[test]
24912798
     fn do_concurrent_ok_with_f2008() {
2492
-        let errs = errors_with_std("\
2799
+        let errs = errors_with_std(
2800
+            "\
24932801
 program test
24942802
   implicit none
24952803
   integer :: i
24962804
   do concurrent (i = 1:10)
24972805
   end do
24982806
 end program
2499
-", FortranStandard::F2008);
2807
+",
2808
+            FortranStandard::F2008,
2809
+        );
25002810
         assert!(!errs.iter().any(|e| e.contains("DO CONCURRENT")));
25012811
     }
25022812
 
25032813
     #[test]
25042814
     fn error_stop_requires_f2008() {
2505
-        let errs = errors_with_std("\
2815
+        let errs = errors_with_std(
2816
+            "\
25062817
 program test
25072818
   implicit none
25082819
   error stop
25092820
 end program
2510
-", FortranStandard::F95);
2511
-        assert!(errs.iter().any(|e| e.contains("ERROR STOP") && e.contains("F2008")));
2821
+",
2822
+            FortranStandard::F95,
2823
+        );
2824
+        assert!(errs
2825
+            .iter()
2826
+            .any(|e| e.contains("ERROR STOP") && e.contains("F2008")));
25122827
     }
25132828
 
25142829
     #[test]
25152830
     fn block_construct_requires_f2008() {
2516
-        let errs = errors_with_std("\
2831
+        let errs = errors_with_std(
2832
+            "\
25172833
 program test
25182834
   implicit none
25192835
   block
25202836
     x = 1
25212837
   end block
25222838
 end program
2523
-", FortranStandard::F95);
2524
-        assert!(errs.iter().any(|e| e.contains("BLOCK") && e.contains("F2008")));
2839
+",
2840
+            FortranStandard::F95,
2841
+        );
2842
+        assert!(errs
2843
+            .iter()
2844
+            .any(|e| e.contains("BLOCK") && e.contains("F2008")));
25252845
     }
25262846
 
25272847
     #[test]
25282848
     fn associate_requires_f2003() {
2529
-        let errs = errors_with_std("\
2849
+        let errs = errors_with_std(
2850
+            "\
25302851
 program test
25312852
   implicit none
25322853
   integer :: n
@@ -2534,14 +2855,19 @@ program test
25342855
   associate (m => n)
25352856
   end associate
25362857
 end program
2537
-", FortranStandard::F95);
2538
-        assert!(errs.iter().any(|e| e.contains("ASSOCIATE") && e.contains("F2003")));
2858
+",
2859
+            FortranStandard::F95,
2860
+        );
2861
+        assert!(errs
2862
+            .iter()
2863
+            .any(|e| e.contains("ASSOCIATE") && e.contains("F2003")));
25392864
     }
25402865
 
25412866
     #[test]
25422867
     fn no_std_violations_when_unset() {
25432868
         // With no --std= set, everything is allowed.
2544
-        let errs = errors_from("\
2869
+        let errs = errors_from(
2870
+            "\
25452871
 program test
25462872
   implicit none
25472873
   integer :: i
@@ -2565,7 +2891,9 @@ end subroutine
25652891
 ",
25662892
             FortranStandard::F95,
25672893
         );
2568
-        assert!(errs.iter().any(|e| e.contains("IMPURE") && e.contains("F2008")));
2894
+        assert!(errs
2895
+            .iter()
2896
+            .any(|e| e.contains("IMPURE") && e.contains("F2008")));
25692897
     }
25702898
 
25712899
     #[test]
@@ -2588,13 +2916,16 @@ end subroutine
25882916
             },
25892917
             span,
25902918
         );
2591
-        let diags = validate_file_with_std(&[unit], &SymbolTable::new(), Some(FortranStandard::F95));
2919
+        let diags =
2920
+            validate_file_with_std(&[unit], &SymbolTable::new(), Some(FortranStandard::F95));
25922921
         let errs: Vec<_> = diags
25932922
             .into_iter()
25942923
             .filter(|d| d.kind == DiagKind::Error)
25952924
             .map(|d| d.msg)
25962925
             .collect();
2597
-        assert!(errs.iter().any(|e| e.contains("SUBMODULE") && e.contains("F2008")));
2926
+        assert!(errs
2927
+            .iter()
2928
+            .any(|e| e.contains("SUBMODULE") && e.contains("F2008")));
25982929
     }
25992930
 
26002931
     #[test]
@@ -2701,7 +3032,9 @@ end program
27013032
 ",
27023033
             FortranStandard::F95,
27033034
         );
2704
-        assert!(errs.iter().any(|e| e.contains("MOVE_ALLOC") && e.contains("F2003")));
3035
+        assert!(errs
3036
+            .iter()
3037
+            .any(|e| e.contains("MOVE_ALLOC") && e.contains("F2003")));
27053038
     }
27063039
 
27073040
     // ---- Elemental ----
src/testing.rsmodified
103 lines changed — click to load
@@ -13,15 +13,15 @@ use std::sync::atomic::{AtomicU64, Ordering};
1313
 use std::time::SystemTime;
1414
 
1515
 use crate::codegen::mir::{
16
-    ArmCond, ConstPoolEntry, MachineFunction, MachineInst, MachineOperand, MBlockId, PhysReg,
16
+    ArmCond, ConstPoolEntry, MBlockId, MachineFunction, MachineInst, MachineOperand, PhysReg,
1717
     RegClass,
1818
 };
1919
 use crate::codegen::{emit, isel, linearscan};
2020
 use crate::driver::OptLevel;
21
-use crate::opt::{build_i128_pipeline, build_pipeline};
22
-use crate::opt::pipeline::OptLevel as IrOptLevel;
2321
 use crate::ir::{lower, printer as ir_printer, verify};
2422
 use crate::lexer::{detect_source_form, tokenize, SourceForm, Token};
23
+use crate::opt::pipeline::OptLevel as IrOptLevel;
24
+use crate::opt::{build_i128_pipeline, build_pipeline};
2525
 use crate::parser::Parser;
2626
 use crate::sema::{resolve, validate};
2727
 
@@ -243,7 +243,10 @@ pub fn capture_from_path(request: &CaptureRequest) -> Result<CaptureResult, Capt
243243
     let mut stages = BTreeMap::new();
244244
     let wants = |stage| request.requested.contains(&stage);
245245
     let needs_backend = request.requested.iter().any(|stage| {
246
-        matches!(stage, Stage::Mir | Stage::Regalloc | Stage::Asm | Stage::Obj | Stage::Run)
246
+        matches!(
247
+            stage,
248
+            Stage::Mir | Stage::Regalloc | Stage::Asm | Stage::Obj | Stage::Run
249
+        )
247250
     });
248251
     let input = request.input.clone();
249252
     let source_form = detect_source_form(&input.to_string_lossy());
@@ -338,7 +341,13 @@ pub fn capture_from_path(request: &CaptureRequest) -> Result<CaptureResult, Capt
338341
         });
339342
     }
340343
 
341
-    let (ir_module, _module_globals) = lower::lower_file(&units, &st, &type_layouts, std::collections::HashMap::new(), std::collections::HashMap::new());
344
+    let (ir_module, _module_globals) = lower::lower_file(
345
+        &units,
346
+        &st,
347
+        &type_layouts,
348
+        std::collections::HashMap::new(),
349
+        std::collections::HashMap::new(),
350
+    );
342351
     let ir_errors = verify::verify_module(&ir_module);
343352
     if !ir_errors.is_empty() {
344353
         let msg = ir_errors
@@ -360,14 +369,12 @@ pub fn capture_from_path(request: &CaptureRequest) -> Result<CaptureResult, Capt
360369
         stages.insert(Stage::Ir, CapturedStage::Text(ir_text.clone()));
361370
     }
362371
     let module_has_i128 = ir_module.contains_i128();
363
-    let needs_optimized_pipeline =
364
-        request.requested.iter().any(|stage| {
365
-            matches!(
366
-                stage,
367
-                Stage::OptIr | Stage::Mir | Stage::Regalloc | Stage::Asm | Stage::Obj | Stage::Run
368
-            )
369
-        })
370
-        && request.opt_level != OptLevel::O0;
372
+    let needs_optimized_pipeline = request.requested.iter().any(|stage| {
373
+        matches!(
374
+            stage,
375
+            Stage::OptIr | Stage::Mir | Stage::Regalloc | Stage::Asm | Stage::Obj | Stage::Run
376
+        )
377
+    }) && request.opt_level != OptLevel::O0;
371378
 
372379
     let optimized_module = if needs_optimized_pipeline {
373380
         let mut optimized = ir_module.clone();
@@ -422,7 +429,9 @@ pub fn capture_from_path(request: &CaptureRequest) -> Result<CaptureResult, Capt
422429
             input: input.clone(),
423430
             opt_level: request.opt_level,
424431
             stage: FailureStage::Ir,
425
-            detail: "backend does not yet support integer(16) / i128 codegen; capture IR at O0 for now".into(),
432
+            detail:
433
+                "backend does not yet support integer(16) / i128 codegen; capture IR at O0 for now"
434
+                    .into(),
426435
             stages,
427436
         });
428437
     }
@@ -560,10 +569,7 @@ fn collect_sandbox_files(
560569
             collect_sandbox_files(root, &path, out)?;
561570
         } else {
562571
             let rel = path.strip_prefix(root).unwrap();
563
-            out.insert(
564
-                rel.to_string_lossy().replace('\\', "/"),
565
-                fs::read(&path)?,
566
-            );
572
+            out.insert(rel.to_string_lossy().replace('\\', "/"), fs::read(&path)?);
567573
         }
568574
     }
569575
     Ok(())
@@ -942,7 +948,9 @@ fn maybe_refresh_runtime_lib(workspace_root: &Path) -> Result<(), String> {
942948
         return Ok(());
943949
     };
944950
     let debug_archive = workspace_root.join("target/debug/libarmfortas_rt.a");
945
-    let archive_mtime = fs::metadata(&debug_archive).ok().and_then(|meta| meta.modified().ok());
951
+    let archive_mtime = fs::metadata(&debug_archive)
952
+        .ok()
953
+        .and_then(|meta| meta.modified().ok());
946954
 
947955
     if archive_mtime.is_some_and(|mtime| mtime >= source_mtime) {
948956
         return Ok(());
@@ -992,7 +1000,8 @@ fn find_workspace_root() -> Option<PathBuf> {
9921000
 
9931001
     for base in bases {
9941002
         for ancestor in base.ancestors() {
995
-            if ancestor.join("Cargo.toml").exists() && ancestor.join("runtime/Cargo.toml").exists() {
1003
+            if ancestor.join("Cargo.toml").exists() && ancestor.join("runtime/Cargo.toml").exists()
1004
+            {
9961005
                 return Some(ancestor.to_path_buf());
9971006
             }
9981007
         }
tests/artifact_audit_29_10.rsmodified
24 lines changed — click to load
@@ -115,7 +115,14 @@ fn optimized_object_snapshot_removes_inlined_helper_symbol() {
115115
 fn object_snapshot_is_deterministic_with_module_globals_across_opt_levels() {
116116
     let source = fixture("module_init.f90");
117117
 
118
-    for opt in [OptLevel::O0, OptLevel::O1, OptLevel::O2, OptLevel::O3, OptLevel::Os, OptLevel::Ofast] {
118
+    for opt in [
119
+        OptLevel::O0,
120
+        OptLevel::O1,
121
+        OptLevel::O2,
122
+        OptLevel::O3,
123
+        OptLevel::Os,
124
+        OptLevel::Ofast,
125
+    ] {
119126
         let first = capture_text(
120127
             CaptureRequest {
121128
                 input: source.clone(),
@@ -133,7 +140,8 @@ fn object_snapshot_is_deterministic_with_module_globals_across_opt_levels() {
133140
             Stage::Obj,
134141
         );
135142
         assert_eq!(
136
-            first, second,
143
+            first,
144
+            second,
137145
             "object snapshot should be deterministic for module globals at {}",
138146
             opt_name(opt)
139147
         );
tests/claims_audit_29_11.rsmodified
30 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -137,7 +139,10 @@ fn o2_realworld_ipo_chain_trims_dead_arg_and_removes_trivial_wrapper() {
137139
         "optimized IR should remove the trivial wrapper helper:\n{}",
138140
         opt_ir
139141
     );
140
-    assert_eq!(obj_a, obj_b, "IPO-audited O2 object snapshot should stay deterministic");
142
+    assert_eq!(
143
+        obj_a, obj_b,
144
+        "IPO-audited O2 object snapshot should stay deterministic"
145
+    );
141146
 }
142147
 
143148
 #[test]
@@ -236,5 +241,8 @@ fn o3_vectorizes_realworld_explicit_do_stage() {
236241
         "vectorized O3 assembly should reference the bulk add kernel:\n{}",
237242
         o3_asm
238243
     );
239
-    assert_eq!(o3_obj_a, o3_obj_b, "vectorized O3 object snapshot should stay deterministic");
244
+    assert_eq!(
245
+        o3_obj_a, o3_obj_b,
246
+        "vectorized O3 object snapshot should stay deterministic"
247
+    );
240248
 }
tests/determinism_sweep.rsmodified
65 lines changed — click to load
@@ -28,7 +28,9 @@ fn find_compiler() -> PathBuf {
2828
 fn find_test_programs() -> PathBuf {
2929
     for c in &["test_programs", "../test_programs"] {
3030
         let p = PathBuf::from(c);
31
-        if p.is_dir() { return p; }
31
+        if p.is_dir() {
32
+            return p;
33
+        }
3234
     }
3335
     panic!("cannot find test_programs/ directory");
3436
 }
@@ -36,7 +38,11 @@ fn find_test_programs() -> PathBuf {
3638
 fn unique_path(prefix: &str, ext: &str) -> PathBuf {
3739
     let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
3840
     std::env::temp_dir().join(format!(
39
-        "afs_det_{}_{}_{}{}", prefix, std::process::id(), id, ext
41
+        "afs_det_{}_{}_{}{}",
42
+        prefix,
43
+        std::process::id(),
44
+        id,
45
+        ext
4046
     ))
4147
 }
4248
 
@@ -45,7 +51,13 @@ fn unique_path(prefix: &str, ext: &str) -> PathBuf {
4551
 fn compile_to_asm(compiler: &Path, source: &Path, opt: &str) -> Option<Vec<u8>> {
4652
     let out = unique_path("sweep", ".s");
4753
     let result = Command::new(compiler)
48
-        .args([source.to_str().unwrap(), opt, "-S", "-o", out.to_str().unwrap()])
54
+        .args([
55
+            source.to_str().unwrap(),
56
+            opt,
57
+            "-S",
58
+            "-o",
59
+            out.to_str().unwrap(),
60
+        ])
4961
         .output()
5062
         .expect("compiler launch failed");
5163
     if !result.status.success() {
@@ -112,7 +124,9 @@ fn all_programs_deterministic_at_o2() {
112124
         if first != second {
113125
             failures.push(format!(
114126
                 "{}: assembly differs between two -O2 compilations ({} vs {} bytes)",
115
-                name, first.len(), second.len(),
127
+                name,
128
+                first.len(),
129
+                second.len(),
116130
             ));
117131
         } else {
118132
             checked += 1;
@@ -121,14 +135,14 @@ fn all_programs_deterministic_at_o2() {
121135
 
122136
     eprintln!(
123137
         "\nDeterminism sweep: {} checked, {} skipped, {} failures out of {} programs",
124
-        checked, skipped, failures.len(), sources.len(),
138
+        checked,
139
+        skipped,
140
+        failures.len(),
141
+        sources.len(),
125142
     );
126143
 
127144
     if !failures.is_empty() {
128
-        panic!(
129
-            "Determinism failures:\n{}",
130
-            failures.join("\n"),
131
-        );
145
+        panic!("Determinism failures:\n{}", failures.join("\n"),);
132146
     }
133147
 
134148
     // Sanity: we should have checked a substantial portion.
tests/fortran_alias_licm.rsmodified
28 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -36,13 +38,13 @@ fn block_section<'a>(func_section: &'a str, prefix: &str) -> &'a str {
3638
     for (idx, _line) in func_section.match_indices('\n') {
3739
         let line_start = idx + 1;
3840
         let tail = &func_section[line_start..];
39
-        let line_text = tail
40
-            .split_once('\n')
41
-            .map(|(line, _)| line)
42
-            .unwrap_or(tail);
41
+        let line_text = tail.split_once('\n').map(|(line, _)| line).unwrap_or(tail);
4342
 
4443
         if start.is_none() {
45
-            if line_text.starts_with("    ") && !line_text.starts_with("      ") && line_text[4..].starts_with(prefix) {
44
+            if line_text.starts_with("    ")
45
+                && !line_text.starts_with("      ")
46
+                && line_text[4..].starts_with(prefix)
47
+            {
4648
                 start = Some(line_start);
4749
             }
4850
             continue;
tests/fuzz_smoke.rsmodified
36 lines changed — click to load
@@ -65,15 +65,21 @@ fn fuzz_parser_deterministic(seed: u64, count: usize) {
6565
 /// Runs without threads — each input goes directly through the parser.
6666
 fn fuzz_parser_with_fortran_fragments(count: usize) {
6767
     let fragments = [
68
-        "program p\nend program\n", "module m\nend module\n",
69
-        "integer :: x\n", "real, allocatable :: a(:,:)\n",
70
-        "do i = 1, 10\nend do\n", "if (x > 0) then\nend if\n",
68
+        "program p\nend program\n",
69
+        "module m\nend module\n",
70
+        "integer :: x\n",
71
+        "real, allocatable :: a(:,:)\n",
72
+        "do i = 1, 10\nend do\n",
73
+        "if (x > 0) then\nend if\n",
7174
         "select case (x)\ncase (1)\nend select\n",
7275
         "type :: t\n  integer :: f\nend type\n",
7376
         "interface\nend interface\n",
74
-        "goto 100\n", "100 continue\n",
77
+        "goto 100\n",
78
+        "100 continue\n",
7579
         "use iso_c_binding, only: c_int\n",
76
-        "", "!\n", "! comment\n",
80
+        "",
81
+        "!\n",
82
+        "! comment\n",
7783
         "end\n",
7884
         "do concurrent (i = 1:10)\nend do\n",
7985
         "block\n  integer :: local\nend block\n",
@@ -98,7 +104,9 @@ fn fuzz_parser_with_fortran_fragments(count: usize) {
98104
         }
99105
 
100106
         if let Ok(tokens) = lexer::tokenize(&src, 0, SourceForm::FreeForm) {
101
-            if tokens.len() > 100 { continue; }
107
+            if tokens.len() > 100 {
108
+                continue;
109
+            }
102110
             let mut parser = Parser::new(&tokens);
103111
             let _ = parser.parse_file();
104112
         }
tests/gvn_dse_audit_29_11.rsmodified
22 lines changed — click to load
@@ -38,10 +38,7 @@ fn block_section<'a>(func_section: &'a str, prefix: &str) -> &'a str {
3838
     for (idx, _line) in func_section.match_indices('\n') {
3939
         let line_start = idx + 1;
4040
         let tail = &func_section[line_start..];
41
-        let line_text = tail
42
-            .split_once('\n')
43
-            .map(|(line, _)| line)
44
-            .unwrap_or(tail);
41
+        let line_text = tail.split_once('\n').map(|(line, _)| line).unwrap_or(tail);
4542
 
4643
         if start.is_none() {
4744
             if line_text.starts_with("    ")
@@ -74,10 +71,7 @@ fn last_block_section<'a>(func_section: &'a str, prefix: &str) -> &'a str {
7471
     for (idx, _line) in func_section.match_indices('\n') {
7572
         let line_start = idx + 1;
7673
         let tail = &func_section[line_start..];
77
-        let line_text = tail
78
-            .split_once('\n')
79
-            .map(|(line, _)| line)
80
-            .unwrap_or(tail);
74
+        let line_text = tail.split_once('\n').map(|(line, _)| line).unwrap_or(tail);
8175
         if line_text.starts_with("    ")
8276
             && !line_text.starts_with("      ")
8377
             && line_text[4..].starts_with(prefix)
tests/i128_cross_object.rsmodified
77 lines changed — click to load
@@ -1,8 +1,8 @@
11
 use std::fs;
22
 use std::path::{Path, PathBuf};
33
 use std::process::Command;
4
-use std::sync::Mutex;
54
 use std::sync::atomic::{AtomicUsize, Ordering};
5
+use std::sync::Mutex;
66
 use std::time::SystemTime;
77
 
88
 use armfortas::driver::{compile, OptLevel, Options};
@@ -100,7 +100,9 @@ fn maybe_refresh_runtime_lib(workspace_root: &Path) {
100100
         return;
101101
     };
102102
     let debug_archive = workspace_root.join("target/debug/libarmfortas_rt.a");
103
-    let archive_mtime = fs::metadata(&debug_archive).ok().and_then(|meta| meta.modified().ok());
103
+    let archive_mtime = fs::metadata(&debug_archive)
104
+        .ok()
105
+        .and_then(|meta| meta.modified().ok());
104106
 
105107
     if archive_mtime.is_some_and(|mtime| mtime >= source_mtime) {
106108
         return;
@@ -208,13 +210,23 @@ fn run_cross_object_case_named(
208210
     opt_level: OptLevel,
209211
     expected_score: char,
210212
 ) {
211
-    let _guard = CROSS_OBJECT_LOCK.lock().unwrap_or_else(|poison| poison.into_inner());
213
+    let _guard = CROSS_OBJECT_LOCK
214
+        .lock()
215
+        .unwrap_or_else(|poison| poison.into_inner());
212216
     let program = fixture(program_name);
213217
     let helper = fixture(helper_name);
214218
     let stem = program.file_stem().unwrap().to_str().unwrap();
215
-    let fortran_obj = unique_temp_path("i128_cross_object", &format!("{}_{}", stem, opt_label(opt_level)), ".o");
219
+    let fortran_obj = unique_temp_path(
220
+        "i128_cross_object",
221
+        &format!("{}_{}", stem, opt_label(opt_level)),
222
+        ".o",
223
+    );
216224
     let helper_obj = unique_temp_path("i128_cross_object_helper", stem, ".o");
217
-    let binary = unique_temp_path("i128_cross_object_bin", &format!("{}_{}", stem, opt_label(opt_level)), "");
225
+    let binary = unique_temp_path(
226
+        "i128_cross_object_bin",
227
+        &format!("{}_{}", stem, opt_label(opt_level)),
228
+        "",
229
+    );
218230
 
219231
     compile_fortran_object(&program, &fortran_obj, opt_level);
220232
     compile_c_object(&helper, &helper_obj);
@@ -249,14 +261,28 @@ fn run_cross_object_case(opt_level: OptLevel) {
249261
     );
250262
 }
251263
 
252
-fn deterministic_cross_object_case_named(program_name: &str, helper_name: &str, opt_level: OptLevel) {
253
-    let _guard = CROSS_OBJECT_LOCK.lock().unwrap_or_else(|poison| poison.into_inner());
264
+fn deterministic_cross_object_case_named(
265
+    program_name: &str,
266
+    helper_name: &str,
267
+    opt_level: OptLevel,
268
+) {
269
+    let _guard = CROSS_OBJECT_LOCK
270
+        .lock()
271
+        .unwrap_or_else(|poison| poison.into_inner());
254272
     let program = fixture(program_name);
255273
     let helper = fixture(helper_name);
256274
     let stem = program.file_stem().unwrap().to_str().unwrap();
257
-    let fortran_obj = unique_temp_path("i128_cross_object", &format!("{}_{}", stem, opt_label(opt_level)), ".o");
275
+    let fortran_obj = unique_temp_path(
276
+        "i128_cross_object",
277
+        &format!("{}_{}", stem, opt_label(opt_level)),
278
+        ".o",
279
+    );
258280
     let helper_obj = unique_temp_path("i128_cross_object_helper", stem, ".o");
259
-    let binary = unique_temp_path("i128_cross_object_bin", &format!("{}_{}", stem, opt_label(opt_level)), "");
281
+    let binary = unique_temp_path(
282
+        "i128_cross_object_bin",
283
+        &format!("{}_{}", stem, opt_label(opt_level)),
284
+        "",
285
+    );
260286
 
261287
     compile_fortran_object(&program, &fortran_obj, opt_level);
262288
     compile_c_object(&helper, &helper_obj);
tests/i128_formatted_read.rsmodified
137 lines changed — click to load
@@ -75,15 +75,26 @@ fn integer16_formatted_read_runs_across_all_opt_levels() {
7575
             requested: BTreeSet::from([Stage::Run]),
7676
             opt_level: level,
7777
         })
78
-        .unwrap_or_else(|e| panic!("formatted integer(16) input should run at {:?}:\n{}", level, e));
78
+        .unwrap_or_else(|e| {
79
+            panic!(
80
+                "formatted integer(16) input should run at {:?}:\n{}",
81
+                level, e
82
+            )
83
+        });
7984
 
8085
         let run = result
8186
             .get(Stage::Run)
8287
             .and_then(CapturedStage::as_run)
8388
             .expect("missing run capture");
8489
 
85
-        assert_eq!(run.exit_code, 0, "expected successful formatted integer(16) read run at {:?}:\n{:#?}", level, run);
86
-        assert!(run.stdout.contains("170141183460469231731687303715884105727"));
90
+        assert_eq!(
91
+            run.exit_code, 0,
92
+            "expected successful formatted integer(16) read run at {:?}:\n{:#?}",
93
+            level, run
94
+        );
95
+        assert!(run
96
+            .stdout
97
+            .contains("170141183460469231731687303715884105727"));
8798
         assert!(run.stdout.contains("42"));
8899
     }
89100
 }
@@ -161,14 +172,23 @@ fn integer16_formatted_read_targets_run_across_all_opt_levels() {
161172
             requested: BTreeSet::from([Stage::Run]),
162173
             opt_level: level,
163174
         })
164
-        .unwrap_or_else(|e| panic!("formatted integer(16) lvalue read should run at {:?}:\n{}", level, e));
175
+        .unwrap_or_else(|e| {
176
+            panic!(
177
+                "formatted integer(16) lvalue read should run at {:?}:\n{}",
178
+                level, e
179
+            )
180
+        });
165181
 
166182
         let run = result
167183
             .get(Stage::Run)
168184
             .and_then(CapturedStage::as_run)
169185
             .expect("missing run capture");
170186
 
171
-        assert_eq!(run.exit_code, 0, "expected successful formatted integer(16) lvalue read run at {:?}:\n{:#?}", level, run);
187
+        assert_eq!(
188
+            run.exit_code, 0,
189
+            "expected successful formatted integer(16) lvalue read run at {:?}:\n{:#?}",
190
+            level, run
191
+        );
172192
         for needle in [
173193
             "11",
174194
             "-170141183460469231731687303715884105727",
@@ -255,16 +275,29 @@ fn integer16_formatted_read_arrays_run_across_all_opt_levels() {
255275
             requested: BTreeSet::from([Stage::Run]),
256276
             opt_level: level,
257277
         })
258
-        .unwrap_or_else(|e| panic!("formatted integer(16) array reads should run at {:?}:\n{}", level, e));
278
+        .unwrap_or_else(|e| {
279
+            panic!(
280
+                "formatted integer(16) array reads should run at {:?}:\n{}",
281
+                level, e
282
+            )
283
+        });
259284
 
260285
         let run = result
261286
             .get(Stage::Run)
262287
             .and_then(CapturedStage::as_run)
263288
             .expect("missing run capture");
264289
 
265
-        assert_eq!(run.exit_code, 0, "expected successful formatted integer(16) array read run at {:?}:\n{:#?}", level, run);
266
-        assert!(run.stdout.contains("11 170141183460469231731687303715884105727 33"));
267
-        assert!(run.stdout.contains("66 -170141183460469231731687303715884105727 44"));
290
+        assert_eq!(
291
+            run.exit_code, 0,
292
+            "expected successful formatted integer(16) array read run at {:?}:\n{:#?}",
293
+            level, run
294
+        );
295
+        assert!(run
296
+            .stdout
297
+            .contains("11 170141183460469231731687303715884105727 33"));
298
+        assert!(run
299
+            .stdout
300
+            .contains("66 -170141183460469231731687303715884105727 44"));
268301
     }
269302
 }
270303
 
@@ -335,14 +368,23 @@ fn integer16_formatted_read_sections_run_across_all_opt_levels() {
335368
             requested: BTreeSet::from([Stage::Run]),
336369
             opt_level: level,
337370
         })
338
-        .unwrap_or_else(|e| panic!("formatted integer(16) section reads should run at {:?}:\n{}", level, e));
371
+        .unwrap_or_else(|e| {
372
+            panic!(
373
+                "formatted integer(16) section reads should run at {:?}:\n{}",
374
+                level, e
375
+            )
376
+        });
339377
 
340378
         let run = result
341379
             .get(Stage::Run)
342380
             .and_then(CapturedStage::as_run)
343381
             .expect("missing run capture");
344382
 
345
-        assert_eq!(run.exit_code, 0, "expected successful formatted integer(16) section read run at {:?}:\n{:#?}", level, run);
383
+        assert_eq!(
384
+            run.exit_code, 0,
385
+            "expected successful formatted integer(16) section read run at {:?}:\n{:#?}",
386
+            level, run
387
+        );
346388
         assert!(run.stdout.contains("101 202"));
347389
         assert!(run.stdout.contains("606 505 404 303"));
348390
     }
@@ -459,14 +501,23 @@ fn integer16_formatted_read_alloc_reverse_section_runs_across_all_opt_levels() {
459501
             requested: BTreeSet::from([Stage::Run]),
460502
             opt_level: level,
461503
         })
462
-        .unwrap_or_else(|e| panic!("allocatable formatted integer(16) reverse section read should run at {:?}:\n{}", level, e));
504
+        .unwrap_or_else(|e| {
505
+            panic!(
506
+                "allocatable formatted integer(16) reverse section read should run at {:?}:\n{}",
507
+                level, e
508
+            )
509
+        });
463510
 
464511
         let run = result
465512
             .get(Stage::Run)
466513
             .and_then(CapturedStage::as_run)
467514
             .expect("missing run capture");
468515
 
469
-        assert_eq!(run.exit_code, 0, "expected successful allocatable reverse section read run at {:?}:\n{:#?}", level, run);
516
+        assert_eq!(
517
+            run.exit_code, 0,
518
+            "expected successful allocatable reverse section read run at {:?}:\n{:#?}",
519
+            level, run
520
+        );
470521
         assert!(run.stdout.contains("8"));
471522
     }
472523
 }
tests/i128_gates.rsmodified
35 lines changed — click to load
@@ -12,13 +12,24 @@ fn fixture(name: &str) -> PathBuf {
1212
 
1313
 #[test]
1414
 fn optimized_i128_capture_is_available_through_ofast() {
15
-    for level in [OptLevel::O1, OptLevel::O2, OptLevel::O3, OptLevel::Os, OptLevel::Ofast] {
15
+    for level in [
16
+        OptLevel::O1,
17
+        OptLevel::O2,
18
+        OptLevel::O3,
19
+        OptLevel::Os,
20
+        OptLevel::Ofast,
21
+    ] {
1622
         capture_from_path(&CaptureRequest {
1723
             input: fixture("integer16_mul.f90"),
1824
             requested: BTreeSet::from([Stage::OptIr]),
1925
             opt_level: level,
2026
         })
21
-        .unwrap_or_else(|e| panic!("optimized i128 capture should succeed at {:?}:\n{}", level, e));
27
+        .unwrap_or_else(|e| {
28
+            panic!(
29
+                "optimized i128 capture should succeed at {:?}:\n{}",
30
+                level, e
31
+            )
32
+        });
2233
     }
2334
 }
2435
 
@@ -33,7 +44,8 @@ fn backend_i128_capture_is_rejected_for_now() {
3344
 
3445
     assert_eq!(err.stage, FailureStage::Ir);
3546
     assert!(
36
-        err.detail.contains("backend does not yet support integer(16) / i128 codegen"),
47
+        err.detail
48
+            .contains("backend does not yet support integer(16) / i128 codegen"),
3749
         "unexpected capture failure:\n{}",
3850
         err
3951
     );
tests/i128_high_opt.rsmodified
12 lines changed — click to load
@@ -121,7 +121,11 @@ fn high_opt_backend_runs_internal_integer16_call() {
121121
             .and_then(CapturedStage::as_run)
122122
             .expect("missing run capture");
123123
 
124
-        assert_eq!(run.exit_code, 0, "expected successful {} integer(16) run:\n{:#?}", label, run);
124
+        assert_eq!(
125
+            run.exit_code, 0,
126
+            "expected successful {} integer(16) run:\n{:#?}",
127
+            label, run
128
+        );
125129
         assert!(
126130
             run.stdout.contains('1'),
127131
             "{} integer(16) internal call program should print score 1:\n{}",
tests/i128_internal_io.rsmodified
198 lines changed — click to load
@@ -82,9 +82,17 @@ fn integer16_internal_io_runs_across_all_opt_levels() {
8282
             .and_then(CapturedStage::as_run)
8383
             .expect("missing run capture");
8484
 
85
-        assert_eq!(run.exit_code, 0, "expected successful internal integer(16) I/O run at {:?}:\n{:#?}", level, run);
86
-        assert!(run.stdout.contains("170141183460469231731687303715884105727"));
87
-        assert!(run.stdout.contains("-170141183460469231731687303715884105727"));
85
+        assert_eq!(
86
+            run.exit_code, 0,
87
+            "expected successful internal integer(16) I/O run at {:?}:\n{:#?}",
88
+            level, run
89
+        );
90
+        assert!(run
91
+            .stdout
92
+            .contains("170141183460469231731687303715884105727"));
93
+        assert!(run
94
+            .stdout
95
+            .contains("-170141183460469231731687303715884105727"));
8896
     }
8997
 }
9098
 
@@ -152,15 +160,26 @@ fn integer16_internal_format_runs_across_all_opt_levels() {
152160
             requested: BTreeSet::from([Stage::Run]),
153161
             opt_level: level,
154162
         })
155
-        .unwrap_or_else(|e| panic!("formatted internal integer(16) write should run at {:?}:\n{}", level, e));
163
+        .unwrap_or_else(|e| {
164
+            panic!(
165
+                "formatted internal integer(16) write should run at {:?}:\n{}",
166
+                level, e
167
+            )
168
+        });
156169
 
157170
         let run = result
158171
             .get(Stage::Run)
159172
             .and_then(CapturedStage::as_run)
160173
             .expect("missing run capture");
161174
 
162
-        assert_eq!(run.exit_code, 0, "expected successful formatted internal integer(16) write run at {:?}:\n{:#?}", level, run);
163
-        assert!(run.stdout.contains("170141183460469231731687303715884105727"));
175
+        assert_eq!(
176
+            run.exit_code, 0,
177
+            "expected successful formatted internal integer(16) write run at {:?}:\n{:#?}",
178
+            level, run
179
+        );
180
+        assert!(run
181
+            .stdout
182
+            .contains("170141183460469231731687303715884105727"));
164183
     }
165184
 }
166185
 
@@ -226,15 +245,26 @@ fn integer16_internal_format_read_runs_across_all_opt_levels() {
226245
             requested: BTreeSet::from([Stage::Run]),
227246
             opt_level: level,
228247
         })
229
-        .unwrap_or_else(|e| panic!("formatted internal integer(16) read should run at {:?}:\n{}", level, e));
248
+        .unwrap_or_else(|e| {
249
+            panic!(
250
+                "formatted internal integer(16) read should run at {:?}:\n{}",
251
+                level, e
252
+            )
253
+        });
230254
 
231255
         let run = result
232256
             .get(Stage::Run)
233257
             .and_then(CapturedStage::as_run)
234258
             .expect("missing run capture");
235259
 
236
-        assert_eq!(run.exit_code, 0, "expected successful formatted internal integer(16) read run at {:?}:\n{:#?}", level, run);
237
-        assert!(run.stdout.contains("170141183460469231731687303715884105727"));
260
+        assert_eq!(
261
+            run.exit_code, 0,
262
+            "expected successful formatted internal integer(16) read run at {:?}:\n{:#?}",
263
+            level, run
264
+        );
265
+        assert!(run
266
+            .stdout
267
+            .contains("170141183460469231731687303715884105727"));
238268
     }
239269
 }
240270
 
@@ -302,14 +332,23 @@ fn integer16_internal_format_read_targets_run_across_all_opt_levels() {
302332
             requested: BTreeSet::from([Stage::Run]),
303333
             opt_level: level,
304334
         })
305
-        .unwrap_or_else(|e| panic!("formatted internal integer(16) lvalue read should run at {:?}:\n{}", level, e));
335
+        .unwrap_or_else(|e| {
336
+            panic!(
337
+                "formatted internal integer(16) lvalue read should run at {:?}:\n{}",
338
+                level, e
339
+            )
340
+        });
306341
 
307342
         let run = result
308343
             .get(Stage::Run)
309344
             .and_then(CapturedStage::as_run)
310345
             .expect("missing run capture");
311346
 
312
-        assert_eq!(run.exit_code, 0, "expected successful formatted internal integer(16) lvalue read run at {:?}:\n{:#?}", level, run);
347
+        assert_eq!(
348
+            run.exit_code, 0,
349
+            "expected successful formatted internal integer(16) lvalue read run at {:?}:\n{:#?}",
350
+            level, run
351
+        );
313352
         for needle in [
314353
             "11",
315354
             "-170141183460469231731687303715884105727",
@@ -391,16 +430,29 @@ fn integer16_internal_format_read_arrays_run_across_all_opt_levels() {
391430
             requested: BTreeSet::from([Stage::Run]),
392431
             opt_level: level,
393432
         })
394
-        .unwrap_or_else(|e| panic!("formatted internal integer(16) array reads should run at {:?}:\n{}", level, e));
433
+        .unwrap_or_else(|e| {
434
+            panic!(
435
+                "formatted internal integer(16) array reads should run at {:?}:\n{}",
436
+                level, e
437
+            )
438
+        });
395439
 
396440
         let run = result
397441
             .get(Stage::Run)
398442
             .and_then(CapturedStage::as_run)
399443
             .expect("missing run capture");
400444
 
401
-        assert_eq!(run.exit_code, 0, "expected successful formatted internal integer(16) array read run at {:?}:\n{:#?}", level, run);
402
-        assert!(run.stdout.contains("11 170141183460469231731687303715884105727 33"));
403
-        assert!(run.stdout.contains("66 -170141183460469231731687303715884105727 44"));
445
+        assert_eq!(
446
+            run.exit_code, 0,
447
+            "expected successful formatted internal integer(16) array read run at {:?}:\n{:#?}",
448
+            level, run
449
+        );
450
+        assert!(run
451
+            .stdout
452
+            .contains("11 170141183460469231731687303715884105727 33"));
453
+        assert!(run
454
+            .stdout
455
+            .contains("66 -170141183460469231731687303715884105727 44"));
404456
     }
405457
 }
406458
 
@@ -466,14 +518,23 @@ fn integer16_internal_format_read_sections_run_across_all_opt_levels() {
466518
             requested: BTreeSet::from([Stage::Run]),
467519
             opt_level: level,
468520
         })
469
-        .unwrap_or_else(|e| panic!("formatted internal integer(16) section reads should run at {:?}:\n{}", level, e));
521
+        .unwrap_or_else(|e| {
522
+            panic!(
523
+                "formatted internal integer(16) section reads should run at {:?}:\n{}",
524
+                level, e
525
+            )
526
+        });
470527
 
471528
         let run = result
472529
             .get(Stage::Run)
473530
             .and_then(CapturedStage::as_run)
474531
             .expect("missing run capture");
475532
 
476
-        assert_eq!(run.exit_code, 0, "expected successful formatted internal integer(16) section read run at {:?}:\n{:#?}", level, run);
533
+        assert_eq!(
534
+            run.exit_code, 0,
535
+            "expected successful formatted internal integer(16) section read run at {:?}:\n{:#?}",
536
+            level, run
537
+        );
477538
         assert!(run.stdout.contains("101 202"));
478539
         assert!(run.stdout.contains("606 505 404 303"));
479540
     }
@@ -541,14 +602,23 @@ fn integer16_internal_format_read_alloc_section_runs_across_all_opt_levels() {
541602
             requested: BTreeSet::from([Stage::Run]),
542603
             opt_level: level,
543604
         })
544
-        .unwrap_or_else(|e| panic!("allocatable internal formatted integer(16) section read should run at {:?}:\n{}", level, e));
605
+        .unwrap_or_else(|e| {
606
+            panic!(
607
+                "allocatable internal formatted integer(16) section read should run at {:?}:\n{}",
608
+                level, e
609
+            )
610
+        });
545611
 
546612
         let run = result
547613
             .get(Stage::Run)
548614
             .and_then(CapturedStage::as_run)
549615
             .expect("missing run capture");
550616
 
551
-        assert_eq!(run.exit_code, 0, "expected successful allocatable internal section read run at {:?}:\n{:#?}", level, run);
617
+        assert_eq!(
618
+            run.exit_code, 0,
619
+            "expected successful allocatable internal section read run at {:?}:\n{:#?}",
620
+            level, run
621
+        );
552622
         assert!(run.stdout.contains("11"));
553623
     }
554624
 }
@@ -621,7 +691,11 @@ fn integer16_internal_format_read_alloc_reverse_section_runs_across_all_opt_leve
621691
             .and_then(CapturedStage::as_run)
622692
             .expect("missing run capture");
623693
 
624
-        assert_eq!(run.exit_code, 0, "expected successful allocatable internal reverse section read run at {:?}:\n{:#?}", level, run);
694
+        assert_eq!(
695
+            run.exit_code, 0,
696
+            "expected successful allocatable internal reverse section read run at {:?}:\n{:#?}",
697
+            level, run
698
+        );
625699
         assert!(run.stdout.contains("8"));
626700
     }
627701
 }
tests/i128_memory_backend.rsmodified
36 lines changed — click to load
@@ -203,7 +203,11 @@ fn simple_local_i128_ordered_branch_runs_at_o0() {
203203
         .and_then(CapturedStage::as_run)
204204
         .expect("missing run capture");
205205
 
206
-    assert_eq!(run.exit_code, 0, "expected successful ordered branch run:\n{:#?}", run);
206
+    assert_eq!(
207
+        run.exit_code, 0,
208
+        "expected successful ordered branch run:\n{:#?}",
209
+        run
210
+    );
207211
     assert!(
208212
         run.stdout.contains('4'),
209213
         "ordered i128 branch program should print score 4:\n{}",
@@ -257,7 +261,11 @@ fn simple_local_i128_select_runs_at_o0() {
257261
         .and_then(CapturedStage::as_run)
258262
         .expect("missing run capture");
259263
 
260
-    assert_eq!(run.exit_code, 0, "expected successful integer(16) select run:\n{:#?}", run);
264
+    assert_eq!(
265
+        run.exit_code, 0,
266
+        "expected successful integer(16) select run:\n{:#?}",
267
+        run
268
+    );
261269
     assert!(
262270
         run.stdout.contains('1'),
263271
         "integer(16) select program should print score 1:\n{}",
@@ -333,7 +341,11 @@ fn simple_internal_i128_call_runs_at_o0() {
333341
         .and_then(CapturedStage::as_run)
334342
         .expect("missing run capture");
335343
 
336
-    assert_eq!(run.exit_code, 0, "expected successful internal integer(16) call run:\n{:#?}", run);
344
+    assert_eq!(
345
+        run.exit_code, 0,
346
+        "expected successful internal integer(16) call run:\n{:#?}",
347
+        run
348
+    );
337349
     assert!(
338350
         run.stdout.contains('1'),
339351
         "internal integer(16) call program should print score 1:\n{}",
tests/i128_o1.rsmodified
24 lines changed — click to load
@@ -69,7 +69,11 @@ fn o1_backend_runs_internal_integer16_call() {
6969
         .and_then(CapturedStage::as_run)
7070
         .expect("missing run capture");
7171
 
72
-    assert_eq!(run.exit_code, 0, "expected successful O1 integer(16) run:\n{:#?}", run);
72
+    assert_eq!(
73
+        run.exit_code, 0,
74
+        "expected successful O1 integer(16) run:\n{:#?}",
75
+        run
76
+    );
7377
     assert!(
7478
         run.stdout.contains('1'),
7579
         "O1 integer(16) internal call program should print score 1:\n{}",
@@ -158,7 +162,11 @@ fn o1_branchy_integer16_program_runs_after_mem2reg() {
158162
         .and_then(CapturedStage::as_run)
159163
         .expect("missing run capture");
160164
 
161
-    assert_eq!(run.exit_code, 0, "expected successful O1 branchy integer(16) run:\n{:#?}", run);
165
+    assert_eq!(
166
+        run.exit_code, 0,
167
+        "expected successful O1 branchy integer(16) run:\n{:#?}",
168
+        run
169
+    );
162170
     assert!(
163171
         run.stdout.contains('1'),
164172
         "branchy O1 integer(16) program should print score 1:\n{}",
tests/i128_o2.rsmodified
12 lines changed — click to load
@@ -105,7 +105,11 @@ fn o2_backend_runs_internal_integer16_call() {
105105
         .and_then(CapturedStage::as_run)
106106
         .expect("missing run capture");
107107
 
108
-    assert_eq!(run.exit_code, 0, "expected successful O2 integer(16) run:\n{:#?}", run);
108
+    assert_eq!(
109
+        run.exit_code, 0,
110
+        "expected successful O2 integer(16) run:\n{:#?}",
111
+        run
112
+    );
109113
     assert!(
110114
         run.stdout.contains('1'),
111115
         "O2 integer(16) internal call program should print score 1:\n{}",
tests/i128_runtime_io.rsmodified
61 lines changed — click to load
@@ -74,15 +74,21 @@ fn integer16_print_runs_across_all_opt_levels() {
7474
             .and_then(CapturedStage::as_run)
7575
             .expect("missing run capture");
7676
 
77
-        assert_eq!(run.exit_code, 0, "expected successful integer(16) print run at {:?}:\n{:#?}", level, run);
77
+        assert_eq!(
78
+            run.exit_code, 0,
79
+            "expected successful integer(16) print run at {:?}:\n{:#?}",
80
+            level, run
81
+        );
7882
         assert!(
79
-            run.stdout.contains("170141183460469231731687303715884105727"),
83
+            run.stdout
84
+                .contains("170141183460469231731687303715884105727"),
8085
             "wide positive integer(16) print should survive at {:?}:\n{}",
8186
             level,
8287
             run.stdout
8388
         );
8489
         assert!(
85
-            run.stdout.contains("-170141183460469231731687303715884105727"),
90
+            run.stdout
91
+                .contains("-170141183460469231731687303715884105727"),
8692
             "wide negative integer(16) print should survive at {:?}:\n{}",
8793
             level,
8894
             run.stdout
@@ -164,22 +170,33 @@ fn integer16_formatted_write_runs_across_all_opt_levels() {
164170
             requested: BTreeSet::from([Stage::Run]),
165171
             opt_level: level,
166172
         })
167
-        .unwrap_or_else(|e| panic!("formatted integer(16) write should run at {:?}:\n{}", level, e));
173
+        .unwrap_or_else(|e| {
174
+            panic!(
175
+                "formatted integer(16) write should run at {:?}:\n{}",
176
+                level, e
177
+            )
178
+        });
168179
 
169180
         let run = result
170181
             .get(Stage::Run)
171182
             .and_then(CapturedStage::as_run)
172183
             .expect("missing run capture");
173184
 
174
-        assert_eq!(run.exit_code, 0, "expected successful formatted integer(16) write run at {:?}:\n{:#?}", level, run);
185
+        assert_eq!(
186
+            run.exit_code, 0,
187
+            "expected successful formatted integer(16) write run at {:?}:\n{:#?}",
188
+            level, run
189
+        );
175190
         assert!(
176
-            run.stdout.contains("170141183460469231731687303715884105727"),
191
+            run.stdout
192
+                .contains("170141183460469231731687303715884105727"),
177193
             "wide positive formatted integer(16) output should survive at {:?}:\n{}",
178194
             level,
179195
             run.stdout
180196
         );
181197
         assert!(
182
-            run.stdout.contains("-170141183460469231731687303715884105727"),
198
+            run.stdout
199
+                .contains("-170141183460469231731687303715884105727"),
183200
             "wide negative formatted integer(16) output should survive at {:?}:\n{}",
184201
             level,
185202
             run.stdout
tests/i128_runtime_read.rsmodified
24 lines changed — click to load
@@ -74,15 +74,21 @@ fn integer16_read_runs_across_all_opt_levels() {
7474
             .and_then(CapturedStage::as_run)
7575
             .expect("missing run capture");
7676
 
77
-        assert_eq!(run.exit_code, 0, "expected successful integer(16) read run at {:?}:\n{:#?}", level, run);
77
+        assert_eq!(
78
+            run.exit_code, 0,
79
+            "expected successful integer(16) read run at {:?}:\n{:#?}",
80
+            level, run
81
+        );
7882
         assert!(
79
-            run.stdout.contains("170141183460469231731687303715884105727"),
83
+            run.stdout
84
+                .contains("170141183460469231731687303715884105727"),
8085
             "wide positive integer(16) read should survive at {:?}:\n{}",
8186
             level,
8287
             run.stdout
8388
         );
8489
         assert!(
85
-            run.stdout.contains("-170141183460469231731687303715884105727"),
90
+            run.stdout
91
+                .contains("-170141183460469231731687303715884105727"),
8692
             "wide negative integer(16) read should survive at {:?}:\n{}",
8793
             level,
8894
             run.stdout
tests/i128_stack_args.rsmodified
50 lines changed — click to load
@@ -66,7 +66,11 @@ fn internal_i128_stack_call_runs_at_o0() {
6666
         .and_then(CapturedStage::as_run)
6767
         .expect("missing run capture");
6868
 
69
-    assert_eq!(run.exit_code, 0, "expected successful integer(16) stack-call run:\n{:#?}", run);
69
+    assert_eq!(
70
+        run.exit_code, 0,
71
+        "expected successful integer(16) stack-call run:\n{:#?}",
72
+        run
73
+    );
7074
     assert!(
7175
         run.stdout.contains('1'),
7276
         "internal integer(16) stack-call program should print score 1:\n{}",
@@ -76,20 +80,35 @@ fn internal_i128_stack_call_runs_at_o0() {
7680
 
7781
 #[test]
7882
 fn internal_i128_stack_call_runs_through_optimized_levels() {
79
-    for level in [OptLevel::O1, OptLevel::O2, OptLevel::O3, OptLevel::Os, OptLevel::Ofast] {
83
+    for level in [
84
+        OptLevel::O1,
85
+        OptLevel::O2,
86
+        OptLevel::O3,
87
+        OptLevel::Os,
88
+        OptLevel::Ofast,
89
+    ] {
8090
         let result = capture_from_path(&CaptureRequest {
8191
             input: fixture("integer16_internal_stack_call.f90"),
8292
             requested: BTreeSet::from([Stage::Run]),
8393
             opt_level: level,
8494
         })
85
-        .unwrap_or_else(|e| panic!("optimized integer(16) stack-call should run at {:?}:\n{}", level, e));
95
+        .unwrap_or_else(|e| {
96
+            panic!(
97
+                "optimized integer(16) stack-call should run at {:?}:\n{}",
98
+                level, e
99
+            )
100
+        });
86101
 
87102
         let run = result
88103
             .get(Stage::Run)
89104
             .and_then(CapturedStage::as_run)
90105
             .expect("missing run capture");
91106
 
92
-        assert_eq!(run.exit_code, 0, "expected successful integer(16) stack-call run at {:?}:\n{:#?}", level, run);
107
+        assert_eq!(
108
+            run.exit_code, 0,
109
+            "expected successful integer(16) stack-call run at {:?}:\n{:#?}",
110
+            level, run
111
+        );
93112
         assert!(
94113
             run.stdout.contains('1'),
95114
             "integer(16) stack-call program should print score 1 at {:?}:\n{}",
tests/incremental.rsmodified
75 lines changed — click to load
@@ -18,9 +18,7 @@ static NEXT_ID: AtomicU64 = AtomicU64::new(0);
1818
 
1919
 fn unique_dir() -> PathBuf {
2020
     let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
21
-    let dir = std::env::temp_dir().join(format!(
22
-        "afs_incr_{}_{}", std::process::id(), id
23
-    ));
21
+    let dir = std::env::temp_dir().join(format!("afs_incr_{}_{}", std::process::id(), id));
2422
     fs::create_dir_all(&dir).unwrap();
2523
     dir
2624
 }
@@ -28,7 +26,9 @@ fn unique_dir() -> PathBuf {
2826
 fn find_compiler() -> PathBuf {
2927
     for c in &["target/release/armfortas", "target/debug/armfortas"] {
3028
         let p = PathBuf::from(c);
31
-        if p.exists() { return fs::canonicalize(&p).unwrap(); }
29
+        if p.exists() {
30
+            return fs::canonicalize(&p).unwrap();
31
+        }
3232
     }
3333
     panic!("armfortas binary not found");
3434
 }
@@ -36,8 +36,11 @@ fn find_compiler() -> PathBuf {
3636
 fn compile(compiler: &Path, source: &Path, obj: &Path, search: &Path) {
3737
     let result = Command::new(compiler)
3838
         .args([
39
-            source.to_str().unwrap(), "-c", "-O0",
40
-            "-o", obj.to_str().unwrap(),
39
+            source.to_str().unwrap(),
40
+            "-c",
41
+            "-O0",
42
+            "-o",
43
+            obj.to_str().unwrap(),
4144
             &format!("-I{}", search.display()),
4245
         ])
4346
         .output()
@@ -96,7 +99,10 @@ fn changed_public_interface_changes_amod() {
9699
     let amod1 = compile_module(&compiler, &dir, "m", v1);
97100
     let amod2 = compile_module(&compiler, &dir, "m", v2);
98101
 
99
-    assert_ne!(amod1, amod2, ".amod should differ when public interface changes");
102
+    assert_ne!(
103
+        amod1, amod2,
104
+        ".amod should differ when public interface changes"
105
+    );
100106
     let _ = fs::remove_dir_all(&dir);
101107
 }
102108
 
@@ -134,7 +140,10 @@ end module
134140
     // header from the body) should be identical.
135141
     let body1 = extract_amod_body(&amod1);
136142
     let body2 = extract_amod_body(&amod2);
137
-    assert_eq!(body1, body2, ".amod interface body changed but only private impl differs");
143
+    assert_eq!(
144
+        body1, body2,
145
+        ".amod interface body changed but only private impl differs"
146
+    );
138147
     let _ = fs::remove_dir_all(&dir);
139148
 }
140149
 
@@ -160,7 +169,10 @@ fn consumer_object_stable_when_amod_unchanged() {
160169
     compile(&compiler, &main_f90, &main_o, &dir);
161170
     let obj2 = fs::read(&main_o).unwrap();
162171
 
163
-    assert_eq!(obj1, obj2, "consumer .o changed despite no source/amod change");
172
+    assert_eq!(
173
+        obj1, obj2,
174
+        "consumer .o changed despite no source/amod change"
175
+    );
164176
     let _ = fs::remove_dir_all(&dir);
165177
 }
166178
 
@@ -170,7 +182,8 @@ fn consumer_object_changes_when_amod_changes() {
170182
     let dir = unique_dir();
171183
 
172184
     let mod_v1 = "module m\n  implicit none\n  integer :: x = 42\nend module\n";
173
-    let mod_v2 = "module m\n  implicit none\n  integer :: x = 42\n  integer :: y = 99\nend module\n";
185
+    let mod_v2 =
186
+        "module m\n  implicit none\n  integer :: x = 42\n  integer :: y = 99\nend module\n";
174187
     let main_src = "program p\n  use m\n  implicit none\n  print *, x\nend program\n";
175188
 
176189
     // Compile module v1 and consumer.
tests/ipo_const_arg.rsmodified
58 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -49,13 +51,12 @@ fn call_arg_counts_for(func_section: &str, callee_marker: &str) -> Vec<usize> {
4951
         .filter_map(|line| {
5052
             let line = line.trim();
5153
             let call = line.find(&format!("call {}", callee_marker))?;
52
-            let inside = line[call..]
53
-                .split_once('(')?
54
-                .1
55
-                .split_once(')')?
56
-                .0
57
-                .trim();
58
-            Some(if inside.is_empty() { 0 } else { inside.split(", ").count() })
54
+            let inside = line[call..].split_once('(')?.1.split_once(')')?.0.trim();
55
+            Some(if inside.is_empty() {
56
+                0
57
+            } else {
58
+                inside.split(", ").count()
59
+            })
5960
         })
6061
         .collect()
6162
 }
@@ -102,8 +103,18 @@ fn o2_specializes_constant_dummy_and_trims_internal_calls() {
102103
     let opt_main = function_section(&opt_ir, "__prog_ipo_const_arg");
103104
     let opt_compute = function_section(&opt_ir, "compute");
104105
 
105
-    assert_eq!(param_count(raw_compute), 2, "raw helper should keep both dummies:\n{}", raw_compute);
106
-    assert_eq!(param_count(opt_compute), 1, "optimized helper should specialize the constant dummy:\n{}", opt_compute);
106
+    assert_eq!(
107
+        param_count(raw_compute),
108
+        2,
109
+        "raw helper should keep both dummies:\n{}",
110
+        raw_compute
111
+    );
112
+    assert_eq!(
113
+        param_count(opt_compute),
114
+        1,
115
+        "optimized helper should specialize the constant dummy:\n{}",
116
+        opt_compute
117
+    );
107118
     assert!(
108119
         opt_compute.contains("const_int 4"),
109120
         "optimized helper should materialize the specialized constant directly:\n{}",
@@ -132,5 +143,8 @@ fn o2_specializes_constant_dummy_and_trims_internal_calls() {
132143
         opt_main
133144
     );
134145
 
135
-    assert_eq!(obj_o2_a, obj_o2_b, "specialized O2 object snapshot should stay deterministic");
146
+    assert_eq!(
147
+        obj_o2_a, obj_o2_b,
148
+        "specialized O2 object snapshot should stay deterministic"
149
+    );
136150
 }
tests/ipo_dead_arg.rsmodified
65 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -49,13 +51,12 @@ fn call_arg_counts_for(func_section: &str, callee_marker: &str) -> Vec<usize> {
4951
         .filter_map(|line| {
5052
             let line = line.trim();
5153
             let call = line.find(&format!("call {}", callee_marker))?;
52
-            let inside = line[call..]
53
-                .split_once('(')?
54
-                .1
55
-                .split_once(')')?
56
-                .0
57
-                .trim();
58
-            Some(if inside.is_empty() { 0 } else { inside.split(", ").count() })
54
+            let inside = line[call..].split_once('(')?.1.split_once(')')?.0.trim();
55
+            Some(if inside.is_empty() {
56
+                0
57
+            } else {
58
+                inside.split(", ").count()
59
+            })
5960
         })
6061
         .collect()
6162
 }
@@ -86,8 +87,18 @@ fn o2_elides_dead_dummy_arg_from_recursive_internal_helper() {
8687
     let opt_main = function_section(&opt_ir, "__prog_ipo_dead_arg");
8788
     let opt_helper = function_section(&opt_ir, "helper");
8889
 
89
-    assert_eq!(param_count(raw_helper), 3, "raw helper should keep all dummy args:\n{}", raw_helper);
90
-    assert_eq!(param_count(opt_helper), 2, "optimized helper should drop the dead dummy arg:\n{}", opt_helper);
90
+    assert_eq!(
91
+        param_count(raw_helper),
92
+        3,
93
+        "raw helper should keep all dummy args:\n{}",
94
+        raw_helper
95
+    );
96
+    assert_eq!(
97
+        param_count(opt_helper),
98
+        2,
99
+        "optimized helper should drop the dead dummy arg:\n{}",
100
+        opt_helper
101
+    );
91102
 
92103
     let raw_call_counts = [
93104
         call_arg_counts_for(raw_main, "@helper"),
@@ -103,6 +114,14 @@ fn o2_elides_dead_dummy_arg_from_recursive_internal_helper() {
103114
     ]
104115
     .concat();
105116
 
106
-    assert_eq!(raw_call_counts, vec![3, 3], "raw IR should pass all three args at both call sites");
107
-    assert_eq!(opt_call_counts, vec![2, 2], "optimized IR should trim the dead arg at both call sites");
117
+    assert_eq!(
118
+        raw_call_counts,
119
+        vec![3, 3],
120
+        "raw IR should pass all three args at both call sites"
121
+    );
122
+    assert_eq!(
123
+        opt_call_counts,
124
+        vec![2, 2],
125
+        "optimized IR should trim the dead arg at both call sites"
126
+    );
108127
 }
tests/ipo_return_prop.rsmodified
38 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -35,13 +37,12 @@ fn call_arg_counts_for(func_section: &str, callee_marker: &str) -> Vec<usize> {
3537
         .filter_map(|line| {
3638
             let line = line.trim();
3739
             let call = line.find(&format!("call {}", callee_marker))?;
38
-            let inside = line[call..]
39
-                .split_once('(')?
40
-                .1
41
-                .split_once(')')?
42
-                .0
43
-                .trim();
44
-            Some(if inside.is_empty() { 0 } else { inside.split(", ").count() })
40
+            let inside = line[call..].split_once('(')?.1.split_once(')')?.0.trim();
41
+            Some(if inside.is_empty() {
42
+                0
43
+            } else {
44
+                inside.split(", ").count()
45
+            })
4546
         })
4647
         .collect()
4748
 }
@@ -103,5 +104,8 @@ fn o2_propagates_trivial_return_and_deletes_helper() {
103104
         "optimized caller should no longer call the passthrough helper:\n{}",
104105
         opt_main
105106
     );
106
-    assert_eq!(obj_a, obj_b, "O2 object snapshot should stay deterministic after return propagation");
107
+    assert_eq!(
108
+        obj_a, obj_b,
109
+        "O2 object snapshot should stay deterministic after return propagation"
110
+    );
107111
 }
tests/licm_lsf_audit_29_11.rsmodified
31 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -36,10 +38,7 @@ fn block_section<'a>(func_section: &'a str, prefix: &str) -> &'a str {
3638
     for (idx, _line) in func_section.match_indices('\n') {
3739
         let line_start = idx + 1;
3840
         let tail = &func_section[line_start..];
39
-        let line_text = tail
40
-            .split_once('\n')
41
-            .map(|(line, _)| line)
42
-            .unwrap_or(tail);
41
+        let line_text = tail.split_once('\n').map(|(line, _)| line).unwrap_or(tail);
4342
 
4443
         if start.is_none() {
4544
             if line_text.starts_with("    ")
@@ -67,7 +66,9 @@ fn block_section<'a>(func_section: &'a str, prefix: &str) -> &'a str {
6766
 }
6867
 
6968
 fn tail_after<'a>(text: &'a str, needle: &str) -> &'a str {
70
-    let start = text.find(needle).unwrap_or_else(|| panic!("missing '{}' in:\n{}", needle, text));
69
+    let start = text
70
+        .find(needle)
71
+        .unwrap_or_else(|| panic!("missing '{}' in:\n{}", needle, text));
7172
     &text[start + needle.len()..]
7273
 }
7374
 
tests/multifile.rsmodified
115 lines changed — click to load
@@ -20,7 +20,9 @@ fn unique_dir() -> PathBuf {
2020
 fn find_compiler() -> PathBuf {
2121
     for c in &["target/release/armfortas", "target/debug/armfortas"] {
2222
         let p = PathBuf::from(c);
23
-        if p.exists() { return p; }
23
+        if p.exists() {
24
+            return p;
25
+        }
2426
     }
2527
     panic!("armfortas binary not found");
2628
 }
@@ -28,7 +30,9 @@ fn find_compiler() -> PathBuf {
2830
 fn find_runtime() -> PathBuf {
2931
     for dir in &["target/release", "target/debug"] {
3032
         let p = PathBuf::from(dir).join("libarmfortas_rt.a");
31
-        if p.exists() { return p; }
33
+        if p.exists() {
34
+            return p;
35
+        }
3236
     }
3337
     panic!("libarmfortas_rt.a not found");
3438
 }
@@ -44,7 +48,12 @@ fn sdk_path() -> String {
4448
 /// Compile a .f90 file with -c, producing .o and optionally .amod.
4549
 fn compile_file(compiler: &Path, source: &Path, output: &Path, search_dir: Option<&Path>) {
4650
     let mut cmd = Command::new(compiler);
47
-    cmd.args([source.to_str().unwrap(), "-c", "-o", output.to_str().unwrap()]);
51
+    cmd.args([
52
+        source.to_str().unwrap(),
53
+        "-c",
54
+        "-o",
55
+        output.to_str().unwrap(),
56
+    ]);
4857
     if let Some(dir) = search_dir {
4958
         cmd.arg(format!("-I{}", dir.display()));
5059
     }
@@ -66,8 +75,17 @@ fn link_files(objects: &[&Path], output: &Path) {
6675
         args.push(o.to_str().unwrap().into());
6776
     }
6877
     args.push(runtime.to_str().unwrap().into());
69
-    args.extend(["-lSystem".into(), "-syslibroot".into(), sdk, "-arch".into(), "arm64".into()]);
70
-    let result = Command::new("ld").args(&args).output().expect("ld launch failed");
78
+    args.extend([
79
+        "-lSystem".into(),
80
+        "-syslibroot".into(),
81
+        sdk,
82
+        "-arch".into(),
83
+        "arm64".into(),
84
+    ]);
85
+    let result = Command::new("ld")
86
+        .args(&args)
87
+        .output()
88
+        .expect("ld launch failed");
7189
     assert!(
7290
         result.status.success(),
7391
         "link failed:\n{}",
@@ -77,9 +95,7 @@ fn link_files(objects: &[&Path], output: &Path) {
7795
 
7896
 /// Run a binary and return its stdout.
7997
 fn run_binary(binary: &Path) -> String {
80
-    let result = Command::new(binary)
81
-        .output()
82
-        .expect("binary launch failed");
98
+    let result = Command::new(binary).output().expect("binary launch failed");
8399
     assert!(
84100
         result.status.success(),
85101
         "{} exited with {:?}\nstderr: {}",
@@ -91,11 +107,7 @@ fn run_binary(binary: &Path) -> String {
91107
 }
92108
 
93109
 /// Full multi-file test: write sources, compile, link, run, check.
94
-fn multifile_test(
95
-    mod_source: &str,
96
-    main_source: &str,
97
-    expected_substring: &str,
98
-) {
110
+fn multifile_test(mod_source: &str, main_source: &str, expected_substring: &str) {
99111
     let compiler = find_compiler();
100112
     let dir = unique_dir();
101113
     let mod_f90 = dir.join("mod.f90");
@@ -209,15 +221,27 @@ fn generic_interface_transitive_use() {
209221
 
210222
     std::fs::write(&base_f90, "module base\n  implicit none\n  interface add\n    module procedure add_int, add_real\n  end interface\ncontains\n  integer function add_int(a, b)\n    integer, intent(in) :: a, b\n    add_int = a + b\n  end function\n  real function add_real(a, b)\n    real, intent(in) :: a, b\n    add_real = a + b\n  end function\nend module\n").unwrap();
211223
     std::fs::write(&middle_f90, "module middle\n  use base\nend module\n").unwrap();
212
-    std::fs::write(&main_f90, "program p\n  use middle\n  print *, add(1, 2)\n  print *, add(1.5, 2.5)\nend program\n").unwrap();
224
+    std::fs::write(
225
+        &main_f90,
226
+        "program p\n  use middle\n  print *, add(1, 2)\n  print *, add(1.5, 2.5)\nend program\n",
227
+    )
228
+    .unwrap();
213229
 
214230
     compile_file(&compiler, &base_f90, &base_o, None);
215231
     compile_file(&compiler, &middle_f90, &middle_o, Some(&dir));
216232
     compile_file(&compiler, &main_f90, &main_o, Some(&dir));
217233
     link_files(&[&main_o, &middle_o, &base_o], &binary);
218234
     let output = run_binary(&binary);
219
-    assert!(output.contains("3"), "expected '3' in output, got:\n{}", output);
220
-    assert!(output.contains("4.0000000E0"), "expected real add result in output, got:\n{}", output);
235
+    assert!(
236
+        output.contains("3"),
237
+        "expected '3' in output, got:\n{}",
238
+        output
239
+    );
240
+    assert!(
241
+        output.contains("4.0000000E0"),
242
+        "expected real add result in output, got:\n{}",
243
+        output
244
+    );
221245
 
222246
     let _ = std::fs::remove_dir_all(&dir);
223247
 }
@@ -238,7 +262,10 @@ fn module_private_default() {
238262
     // Check .amod only has pub_val.
239263
     let amod = std::fs::read_to_string(dir.join("priv_mod.amod")).unwrap();
240264
     assert!(amod.contains("pub_val"), "pub_val should be in .amod");
241
-    assert!(!amod.contains("priv_val"), "priv_val should NOT be in .amod");
265
+    assert!(
266
+        !amod.contains("priv_val"),
267
+        "priv_val should NOT be in .amod"
268
+    );
242269
 
243270
     let _ = std::fs::remove_dir_all(&dir);
244271
 }
tests/multifile_gen.rsmodified
142 lines changed — click to load
@@ -13,9 +13,8 @@ static NEXT_ID: AtomicU64 = AtomicU64::new(0);
1313
 
1414
 fn unique_dir(prefix: &str) -> PathBuf {
1515
     let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
16
-    let dir = std::env::temp_dir().join(format!(
17
-        "afs_gen_{}_{}_{}", prefix, std::process::id(), id
18
-    ));
16
+    let dir =
17
+        std::env::temp_dir().join(format!("afs_gen_{}_{}_{}", prefix, std::process::id(), id));
1918
     fs::create_dir_all(&dir).unwrap();
2019
     dir
2120
 }
@@ -23,7 +22,9 @@ fn unique_dir(prefix: &str) -> PathBuf {
2322
 fn find_compiler() -> PathBuf {
2423
     for c in &["target/release/armfortas", "target/debug/armfortas"] {
2524
         let p = PathBuf::from(c);
26
-        if p.exists() { return fs::canonicalize(&p).unwrap(); }
25
+        if p.exists() {
26
+            return fs::canonicalize(&p).unwrap();
27
+        }
2728
     }
2829
     panic!("armfortas binary not found");
2930
 }
@@ -31,7 +32,9 @@ fn find_compiler() -> PathBuf {
3132
 fn find_runtime() -> PathBuf {
3233
     for dir in &["target/release", "target/debug"] {
3334
         let p = PathBuf::from(dir).join("libarmfortas_rt.a");
34
-        if p.exists() { return p; }
35
+        if p.exists() {
36
+            return p;
37
+        }
3538
     }
3639
     panic!("libarmfortas_rt.a not found");
3740
 }
@@ -47,8 +50,11 @@ fn sdk_path() -> String {
4750
 fn compile_file(compiler: &Path, source: &Path, output: &Path, search_dir: &Path, opt: &str) {
4851
     let result = Command::new(compiler)
4952
         .args([
50
-            source.to_str().unwrap(), "-c", opt,
51
-            "-o", output.to_str().unwrap(),
53
+            source.to_str().unwrap(),
54
+            "-c",
55
+            opt,
56
+            "-o",
57
+            output.to_str().unwrap(),
5258
             &format!("-I{}", search_dir.display()),
5359
         ])
5460
         .output()
@@ -69,8 +75,17 @@ fn link_files(objects: &[PathBuf], output: &Path) {
6975
         args.push(o.to_str().unwrap().into());
7076
     }
7177
     args.push(runtime.to_str().unwrap().into());
72
-    args.extend(["-lSystem".into(), "-syslibroot".into(), sdk, "-arch".into(), "arm64".into()]);
73
-    let result = Command::new("ld").args(&args).output().expect("ld launch failed");
78
+    args.extend([
79
+        "-lSystem".into(),
80
+        "-syslibroot".into(),
81
+        sdk,
82
+        "-arch".into(),
83
+        "arm64".into(),
84
+    ]);
85
+    let result = Command::new("ld")
86
+        .args(&args)
87
+        .output()
88
+        .expect("ld launch failed");
7489
     assert!(
7590
         result.status.success(),
7691
         "link failed:\n{}",
@@ -83,7 +98,8 @@ fn run_binary(binary: &Path) -> String {
8398
     assert!(
8499
         result.status.success(),
85100
         "{} exited with {:?}\nstderr: {}",
86
-        binary.display(), result.status.code(),
101
+        binary.display(),
102
+        result.status.code(),
87103
         String::from_utf8_lossy(&result.stderr)
88104
     );
89105
     String::from_utf8_lossy(&result.stdout).into_owned()
@@ -114,16 +130,16 @@ fn gen_chain(depth: usize) -> (Vec<(String, String)>, String, &'static str) {
114130
             format!(
115131
                 "module mod_{i}\n  use mod_{next}\n  implicit none\n  \
116132
                  integer, parameter :: val_{i} = val_{next} + {i}\nend module\n",
117
-                i = i, next = i + 1
133
+                i = i,
134
+                next = i + 1
118135
             ),
119136
         ));
120137
     }
121138
 
122139
     // Main program uses mod_1 and prints the accumulated value.
123140
     let expected: usize = (1..=depth).sum();
124
-    let main_src = format!(
125
-        "program p\n  use mod_1\n  implicit none\n  print *, val_1\nend program\n"
126
-    );
141
+    let main_src =
142
+        format!("program p\n  use mod_1\n  implicit none\n  print *, val_1\nend program\n");
127143
 
128144
     // Files are already in compilation order: leaf first, then towards root.
129145
     let expected_str = Box::leak(format!("{}", expected).into_boxed_str());
@@ -211,7 +227,10 @@ fn run_generated_test(
211227
     assert!(
212228
         output.contains(expected),
213229
         "{} [{}]: expected '{}' in output, got:\n{}",
214
-        label, opt, expected, output
230
+        label,
231
+        opt,
232
+        expected,
233
+        output
215234
     );
216235
 
217236
     let _ = fs::remove_dir_all(&dir);
@@ -303,7 +322,11 @@ fn run_cross_opt_test(
303322
     assert!(
304323
         output.contains(expected),
305324
         "{}: mod@{} + main@{}: expected '{}' in output, got:\n{}",
306
-        label, mod_opt, main_opt, expected, output
325
+        label,
326
+        mod_opt,
327
+        main_opt,
328
+        expected,
329
+        output
307330
     );
308331
 
309332
     let _ = fs::remove_dir_all(&dir);
@@ -336,11 +359,25 @@ fn abi_matrix_diamond4_mod_o2_main_o0() {
336359
 #[test]
337360
 fn abi_matrix_chain5_mod_o0_main_ofast() {
338361
     let (files, main_src, expected) = gen_chain(5);
339
-    run_cross_opt_test(files, main_src, expected, "-O0", "-Ofast", "abi_chain5_0_fast");
362
+    run_cross_opt_test(
363
+        files,
364
+        main_src,
365
+        expected,
366
+        "-O0",
367
+        "-Ofast",
368
+        "abi_chain5_0_fast",
369
+    );
340370
 }
341371
 
342372
 #[test]
343373
 fn abi_matrix_chain5_mod_ofast_main_o0() {
344374
     let (files, main_src, expected) = gen_chain(5);
345
-    run_cross_opt_test(files, main_src, expected, "-Ofast", "-O0", "abi_chain5_fast_0");
375
+    run_cross_opt_test(
376
+        files,
377
+        main_src,
378
+        expected,
379
+        "-Ofast",
380
+        "-O0",
381
+        "abi_chain5_fast_0",
382
+    );
346383
 }
tests/ofast_fast_math.rsmodified
31 lines changed — click to load
@@ -30,7 +30,9 @@ fn capture_run(request: CaptureRequest) -> RunCapture {
3030
 
3131
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
3232
     let header = format!("  func @{}", name);
33
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
33
+    let start = ir
34
+        .find(&header)
35
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
3436
     let rest = &ir[start..];
3537
     let end = rest
3638
         .find("\n  }\n")
@@ -109,7 +111,18 @@ fn ofast_reassociates_float_constant_chain_but_o3_stays_strict() {
109111
         Stage::Obj,
110112
     );
111113
 
112
-    assert_eq!(parse_last_int(&o3_run.stdout), 0, "strict O3 run should keep IEEE-style rounding loss");
113
-    assert_eq!(parse_last_int(&ofast_run.stdout), 1, "Ofast run should expose fast-math reassociation");
114
-    assert_eq!(ofast_obj_a, ofast_obj_b, "Ofast object snapshot should stay deterministic");
114
+    assert_eq!(
115
+        parse_last_int(&o3_run.stdout),
116
+        0,
117
+        "strict O3 run should keep IEEE-style rounding loss"
118
+    );
119
+    assert_eq!(
120
+        parse_last_int(&ofast_run.stdout),
121
+        1,
122
+        "Ofast run should expose fast-math reassociation"
123
+    );
124
+    assert_eq!(
125
+        ofast_obj_a, ofast_obj_b,
126
+        "Ofast object snapshot should stay deterministic"
127
+    );
115128
 }
tests/opt_audit_29_11.rsmodified
21 lines changed — click to load
@@ -25,9 +25,7 @@ fn function_slice<'a>(ir: &'a str, name: &str) -> &'a str {
2525
         .find(&marker)
2626
         .unwrap_or_else(|| panic!("missing function {} in IR:\n{}", name, ir));
2727
     let rest = &ir[start..];
28
-    let end = rest
29
-        .find("\n  func @")
30
-        .unwrap_or(rest.len());
28
+    let end = rest.find("\n  func @").unwrap_or(rest.len());
3129
     &rest[..end]
3230
 }
3331
 
@@ -112,7 +110,10 @@ fn sasum_cleanup_eliminates_chunked_loop_bounds_checks_at_o2() {
112110
 
113111
 #[test]
114112
 fn realworld_29_8_kernels_have_deterministic_o2_objects() {
115
-    for name in ["realworld_sasum_cleanup.f90", "realworld_three_point_apply.f90"] {
113
+    for name in [
114
+        "realworld_sasum_cleanup.f90",
115
+        "realworld_three_point_apply.f90",
116
+    ] {
116117
         let source = fixture(name);
117118
         let first = capture_text(
118119
             CaptureRequest {
tests/program_entry_audit.rsmodified
11 lines changed — click to load
@@ -67,7 +67,10 @@ fn capture_program_entry_fixture_runs_at_o2() {
6767
         opt_level: OptLevel::O2,
6868
     });
6969
 
70
-    assert_eq!(run.exit_code, 0, "program should run successfully:\n{run:#?}");
70
+    assert_eq!(
71
+        run.exit_code, 0,
72
+        "program should run successfully:\n{run:#?}"
73
+    );
7174
     assert!(
7275
         run.stdout.split_whitespace().any(|field| field == "99"),
7376
         "program body should execute and print the helper-written value:\n{}",
tests/pure_call_reuse.rsmodified
22 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
@@ -57,10 +59,8 @@ fn o2_reuses_pure_recursive_call_in_program_caller() {
5759
     let raw_main = function_section(&raw_ir, "__prog_pure_recursive_reuse");
5860
     let opt_main = function_section(&opt_ir, "__prog_pure_recursive_reuse");
5961
 
60
-    let raw_pure_calls =
61
-        count(raw_main, "call @heavy_fact(") + count(raw_main, "call @func_");
62
-    let opt_pure_calls =
63
-        count(opt_main, "call @heavy_fact(") + count(opt_main, "call @func_");
62
+    let raw_pure_calls = count(raw_main, "call @heavy_fact(") + count(raw_main, "call @func_");
63
+    let opt_pure_calls = count(opt_main, "call @heavy_fact(") + count(opt_main, "call @func_");
6464
 
6565
     assert_eq!(
6666
         raw_pure_calls, 2,
tests/pure_dead_call_elim.rsmodified
10 lines changed — click to load
@@ -21,7 +21,9 @@ fn capture_text(request: CaptureRequest, stage: Stage) -> String {
2121
 
2222
 fn function_section<'a>(ir: &'a str, name: &str) -> &'a str {
2323
     let header = format!("  func @{}", name);
24
-    let start = ir.find(&header).unwrap_or_else(|| panic!("missing function section for {}", name));
24
+    let start = ir
25
+        .find(&header)
26
+        .unwrap_or_else(|| panic!("missing function section for {}", name));
2527
     let rest = &ir[start..];
2628
     let end = rest
2729
         .find("\n  }\n")
tests/vectorize_do_loop.rsmodified
9 lines changed — click to load
@@ -92,5 +92,8 @@ fn o3_vectorizes_full_extent_do_loop_and_keeps_objects_deterministic() {
9292
         "O3 assembly should reference the bulk add kernel:\n{}",
9393
         o3_asm
9494
     );
95
-    assert_eq!(o3_obj_a, o3_obj_b, "O3 vectorized object snapshot should stay deterministic");
95
+    assert_eq!(
96
+        o3_obj_a, o3_obj_b,
97
+        "O3 vectorized object snapshot should stay deterministic"
98
+    );
9699
 }
Diff truncated: 112 files; expand each to load its hunks.