diff --git a/.gitignore b/.gitignore index 85b0cba6..4aa4ecd2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ yarn-error.log* # Local deployment home files /.npm /.config + +# clangd +/Benchmark/.cache diff --git a/Benchmark/src/CMakeLists.txt b/Benchmark/src/CMakeLists.txt index 9f2a35a9..001e725b 100644 --- a/Benchmark/src/CMakeLists.txt +++ b/Benchmark/src/CMakeLists.txt @@ -23,3 +23,4 @@ add_benchmark(PWR080) add_benchmark(PWR081) add_benchmark(PWR082) add_benchmark(PWR083) +add_benchmark(PWR087) diff --git a/Benchmark/src/PWR070.cpp b/Benchmark/src/PWR070.cpp index da8ced75..11f91957 100644 --- a/Benchmark/src/PWR070.cpp +++ b/Benchmark/src/PWR070.cpp @@ -2,9 +2,9 @@ // Forward-declare the functions to benchmark extern "C" { -void clamp_even_data_points_f(int n, double *X, int min_value, int max_value); -void clamp_even_data_points_improved_f(int n, double *X, int min_value, - int max_value); +void clamp_data_points_f(int n, double *X, int min_value, int max_value); +void clamp_data_points_improved_f(int n, double *X, int min_value, + int max_value); } // Size adjusted to fit execution on micro-seconds @@ -18,7 +18,7 @@ static void FortranExampleBench(benchmark::State &state) { auto X = OpenCatalog::CreateRandomVector(N); for (auto _ : state) { - clamp_even_data_points_f(N, X.data(), MIN_VALUE, MAX_VALUE); + clamp_data_points_f(N, X.data(), MIN_VALUE, MAX_VALUE); benchmark::DoNotOptimize(X); } } @@ -27,7 +27,7 @@ static void FortranImprovedBench(benchmark::State &state) { auto X = OpenCatalog::CreateRandomVector(N); for (auto _ : state) { - clamp_even_data_points_improved_f(N, X.data(), MIN_VALUE, MAX_VALUE); + clamp_data_points_improved_f(N, X.data(), MIN_VALUE, MAX_VALUE); benchmark::DoNotOptimize(X); } } diff --git a/Benchmark/src/PWR087.cpp b/Benchmark/src/PWR087.cpp new file mode 100644 index 00000000..06cd0878 --- /dev/null +++ b/Benchmark/src/PWR087.cpp @@ -0,0 +1,38 @@ +#include "Benchmark.h" + +// Forward-declare the functions to benchmark +extern "C" { +void clamp_even_data_points_f(int n, double *X, int min_value, int max_value); +void clamp_even_data_points_improved_f(int n, double *X, int min_value, + int max_value); +} + +// Size adjusted to fit execution on micro-seconds +constexpr int N = 1024 * 1024; +constexpr double MIN_VALUE = 2.71; +constexpr double MAX_VALUE = 3.14; + +#if OCB_ENABLE_Fortran + +static void FortranExampleBench(benchmark::State &state) { + auto X = OpenCatalog::CreateRandomVector(N); + + for (auto _ : state) { + clamp_even_data_points_f(N, X.data(), MIN_VALUE, MAX_VALUE); + benchmark::DoNotOptimize(X); + } +} + +static void FortranImprovedBench(benchmark::State &state) { + auto X = OpenCatalog::CreateRandomVector(N); + + for (auto _ : state) { + clamp_even_data_points_improved_f(N, X.data(), MIN_VALUE, MAX_VALUE); + benchmark::DoNotOptimize(X); + } +} + +OC_BENCHMARK("PWR087 Fortran Example", FortranExampleBench); +OC_BENCHMARK("PWR087 Fortran Improved", FortranImprovedBench); + +#endif diff --git a/Checks/PWR070/README.md b/Checks/PWR070/README.md index b8a11216..51ea8f67 100644 --- a/Checks/PWR070/README.md +++ b/Checks/PWR070/README.md @@ -6,29 +6,28 @@ When procedures receive arrays in explicit-shape or assumed-size form, programmers are required to manually pass array properties as additional arguments. This practice limits the compiler's ability to perform compatibility checks, increasing the risk of difficult-to-diagnose runtime bugs. -Additionally, these types of arrays can result in suboptimal performance -compared to assumed-shape arrays. ### Actions -To improve both code safety and performance, transform explicit-shape and -assumed-size array dummy arguments to assumed-shape form. +To improve code safety, transform explicit-shape and assumed-size array dummy +arguments to assumed-shape form. ### Relevance Fortran supports various methods for passing allocated arrays to procedures. Typically, assumed-shape arrays should be preferred over explicit-shape and -assumed-size arrays, as they provide equivalent functionality while being safer -and more efficient: +assumed-size arrays, as they provide equivalent functionality while being +safer: -- **Assumed-shape arrays** are simply declared with a colon for each dimension; - e.g., `real :: arr(:)`, `real :: arr(:, :)`. They offer several benefits: +- **Assumed-shape arrays** are declared with a colon for each dimension; e.g., + `real :: arr(:)`, `real :: arr(:, :)`. They offer several benefits: - Compile-time checks for the compatibility of the passed array's rank. - Automatic deduction of the size of each dimension from the passed array, accessible via `shape(arr)` and `size(arr, dim)`. - **Explicit-shape and assumed-size arrays** require manual specification of - dimension sizes as separate arguments, increasing the likelihood of errors: + dimension sizes, often as separate arguments, increasing the likelihood of + errors: - Explicit-shape arrays specify the size of all dimensions; e.g., `real :: arr(i, j)`. - Assumed-size arrays leave the size of the last dimension unspecified; e.g., @@ -36,10 +35,13 @@ and more efficient: - In general, they lack compile-time checks for consistency between the provided and the expected array. -Additionally, explicit-shape and assumed-size dummy arguments require contiguous -memory. This forces the creation of intermediate data copies when working with -array slices or strided accesses. In contrast, assumed-shape arrays can handle -these scenarios directly, leading to enhanced performance. +> [!NOTE] +> Additionally, explicit-shape and assumed-size dummy arguments require +> contiguous memory. The compiler may silently create contiguous temporary +> copies when passing non-contiguous data, such as array slices. In contrast, +> assumed-shape arrays can handle some of these scenarios directly, potentially +> leading to enhanced performance. See [PWR087](../PWR087/README.md) for more +> details. ### Code examples @@ -172,17 +174,11 @@ $ ./a.out Row 2 Sum: 6.00000000 ``` -> [!TIP] -> As explained previously, if the subroutines operate on a slice of the matrix, -> assumed-shape arrays can manage the slice directly, potentially improving -> performance. -> -> Check the PWR070 benchmark for a demonstration! - > [!WARNING] > Beware that any procedures involving assumed-shape array arguments must have > explicit interfaces at the point of call. If not, the updated code won't -> compile. +> compile. `sum_rows_assumed_shape()` provides an explicit interface due to +> being contained inside its caller. > > Check the [PWR068 entry](../PWR068/) for more details on implicit and explicit > interfaces! diff --git a/Checks/PWR070/benchmark/example.f90 b/Checks/PWR070/benchmark/example.f90 index 14925c78..866735d7 100644 --- a/Checks/PWR070/benchmark/example.f90 +++ b/Checks/PWR070/benchmark/example.f90 @@ -23,7 +23,7 @@ subroutine clamp_values_f(n, X, min_value, max_value) end subroutine clamp_values_f end module mod_explicit_shape -subroutine clamp_even_data_points_f(n, X, min_value, max_value) bind(c) +subroutine clamp_data_points_f(n, X, min_value, max_value) bind(c) use iso_c_binding, only : c_double, c_int use mod_explicit_shape, only : clamp_values_f @@ -32,5 +32,5 @@ subroutine clamp_even_data_points_f(n, X, min_value, max_value) bind(c) real(kind=c_double), dimension(n), intent(inout) :: X real(kind=c_double), intent(in), value :: min_value, max_value - call clamp_values_f(n/2, X(2:n:2), min_value, max_value) -end subroutine clamp_even_data_points_f + call clamp_values_f(n, X, min_value, max_value) +end subroutine clamp_data_points_f diff --git a/Checks/PWR070/benchmark/solution.f90 b/Checks/PWR070/benchmark/solution.f90 index 0a1512dc..adf3a7c6 100644 --- a/Checks/PWR070/benchmark/solution.f90 +++ b/Checks/PWR070/benchmark/solution.f90 @@ -22,7 +22,7 @@ subroutine clamp_values_improved_f(X, min_value, max_value) end subroutine clamp_values_improved_f end module mod_assumed_shape -subroutine clamp_even_data_points_improved_f(n, X, min_value, max_value) bind(c) +subroutine clamp_data_points_improved_f(n, X, min_value, max_value) bind(c) use iso_c_binding, only : c_double, c_int use mod_assumed_shape, only : clamp_values_improved_f @@ -31,5 +31,5 @@ subroutine clamp_even_data_points_improved_f(n, X, min_value, max_value) bind(c) real(kind=c_double), dimension(n), intent(inout) :: X real(kind=c_double), intent(in), value :: min_value, max_value - call clamp_values_improved_f(X(2:n:2), min_value, max_value) -end subroutine clamp_even_data_points_improved_f + call clamp_values_improved_f(X, min_value, max_value) +end subroutine clamp_data_points_improved_f diff --git a/Checks/PWR087/README.md b/Checks/PWR087/README.md new file mode 100644 index 00000000..0a2f9e4c --- /dev/null +++ b/Checks/PWR087/README.md @@ -0,0 +1,181 @@ +# PWR087: Declare array dummy arguments as assumed-shape arrays to favor compiler optimizations + +### Issue + +Assumed-shape dummy arguments require calls to be made through an explicit +interface so the caller can pass the array's runtime descriptor (describing +bounds, strides, etc.). With this information available, the compiler may +generate more efficient code and might avoid creating expensive temporary +copies when passing non-contiguous actual arguments (e.g., array slices). + +### Actions + +Transform explicit-shape and assumed-size array dummy arguments to +assumed-shape form to favor compiler optimizations. + +### Relevance + +Fortran supports various methods for passing allocated arrays to procedures. +Typically, assumed-shape arrays should be preferred over explicit-shape and +assumed-size arrays, as they give the compiler more opportunities to check and +optimize calls: + +- **Assumed-shape arrays** are declared with a colon for each dimension; e.g., + `real :: arr(:)`, `real :: arr(:, :)`: + - Procedure calls require an explicit interface because the caller implicitly + passes the array's runtime descriptor (describing properties such as array + bounds, strides, etc.). + +- **Explicit-shape and assumed-size arrays** require manual specification of + dimension sizes, often as separate arguments: + - Explicit-shape arrays specify the size of all dimensions; e.g., `real :: + arr(i, j)`. + - Assumed-size arrays leave the size of the last dimension unspecified; e.g., + `real :: arr(n, *)`. + - Procedure calls can be made through implicit interfaces. + +Overall, assumed-shape arrays introduce the following benefits: + +1. **Mandatory explicit interface:** The compiler has more information about +the called procedure and its arguments (types, intents, ranks, etc.), which can +facilitate compiler optimizations. + +2. **Avoidance of hidden array temporaries:** With explicit-shape and +assumed-size dummy arguments, passing a non-contiguous actual argument may +cause the compiler to silently create a contiguous temporary copy, which can be +expensive. Assumed-shape arrays can avoid this for certain scenarios (e.g., +regularly strided array sections) because the array descriptor describes how to +traverse memory. + +> [!TIP] +> Many compilers provide flags to warn about these hidden copies. For +> example, `gfortran` supports `-Warray-temporaries`. + +> [!TIP] +> Strided memory access is not always faster than packing data into a +> contiguous temporary; for example, a unit stride access is often more +> favorable for vectorization. Ultimately, the best choice depends on the +> computational kernel and the data. If a kernel benefits from packing, it can +> be forced even for an assumed-shape dummy argument by adding the `contiguous` +> attribute. + +#### Summary + +In terms of performance optimization: + +- **Contiguous actual arguments:** Assumed-shape performance is typically on + par with explicit-shape and assumed-size arrays. + +- **Non-contiguous actual arguments:** Performance depends on whether direct + strided access or packing is better for the kernel. If packing is better, + consider using, for example, an assumed-shape array with the `contiguous` + attribute. + +> [!NOTE] +> Assumed-shape arrays significantly improve code quality and +> maintainability, making them worthwhile even if performance gains are not +> obtained. See [PWR070](../PWR070/README.md) for more details. + +### Code examples + +The following example shows a function that processes an array to clamp its +values to a minimum and maximum value. The initial example uses an +explicit-shape array dummy argument; note how the size `n` of the array is +passed as an additional argument to `clamp_values()`: + +```fortran {5,9,10} showLineNumbers +! example.f90 +module example + implicit none +contains +subroutine clamp_values(n, X, min_value, max_value) + use iso_fortran_env, only: real32 + + implicit none + integer, intent(in) :: n + real(kind=real32), dimension(n), intent(inout) :: X + real(kind=real32), intent(in) :: min_value, max_value + + integer :: i + + do i = 1, n + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values +end module example +``` + +Making the switch to an assumed-shape array is as simple as dropping the `n` +argument, changing `X` to an assumed-shape dummy argument, and querying its +length using the `size()` intrinsic: + +```fortran {5,9,14} showLineNumbers +! solution.f90 +module solution + implicit none +contains +subroutine clamp_values(X, min_value, max_value) + use iso_fortran_env, only: real32 + + implicit none + real(kind=real32), dimension(:), intent(inout) :: X + real(kind=real32), intent(in) :: min_value, max_value + + integer :: i + + do i = 1, size(X, 1) + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values +end module solution +``` + +> [!TIP] +> Now that `clamp_values()` uses an assumed-shape dummy argument, its +> performance might improve when calling the procedure to operate on +> non-contiguous data. +> +> Check the PWR087 benchmark for a demonstration! + +> [!WARNING] +> Beware that any procedures involving assumed-shape array arguments +> must have explicit interfaces at the point of call. If not, the updated code +> won't compile. `clamp_values()` provides an explicit interface to callers due +> to being inside a `module`. +> +> Check the [PWR068 entry](../PWR068/) for more details on implicit and +> explicit interfaces! + +### Related resources + +- [PWR087 + examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR087/) + +### References + +- ["Arrays — Fortran Programming +Language"](https://fortran-lang.org/learn/best_practices/arrays/), Fortran +Community. [last checked February 2026] + +- ["Passing arrays to subroutines in Fortran: Assumed shape vs explicit +shape"](https://stackoverflow.com/questions/75051887/passing-arrays-to-subroutines-in-fortran-assumed-shape-vs-explicit-shape), +Stack Overflow Community. [last checked February 2026] + +- ["Fortran Modernisation +Workshop"](https://blog.rwth-aachen.de/hpc_import_20210107/attachments/39157901/39420371.pdf), +The Numerical Algorithms Group. [last checked February 2026] + +- ["-Warray-temporaries"](https://gcc.gnu.org/onlinedocs/gfortran/Error-and-Warning-Options.html#index-Warray-temporaries), + Free Software Foundation, Inc. [last checked February 2026] + +- ["Assumed-shape arrays + repacking"](https://flang.llvm.org/docs/ArrayRepacking.html), The Flang Team. + [last checked February 2026] diff --git a/Checks/PWR087/benchmark/example.f90 b/Checks/PWR087/benchmark/example.f90 new file mode 100644 index 00000000..f03a5ca9 --- /dev/null +++ b/Checks/PWR087/benchmark/example.f90 @@ -0,0 +1,37 @@ +! PWR087: Declare array dummy arguments as assumed-shape arrays to favor +! compiler optimizations + +module mod_explicit_shape + implicit none +contains +subroutine clamp_values_f(n, X, min_value, max_value) + use iso_c_binding, only : c_double, c_int + + implicit none + integer(kind=c_int), intent(in) :: n + real(kind=c_double), dimension(n), intent(inout) :: X + real(kind=c_double), intent(in) :: min_value, max_value + + integer(kind=c_int) :: i + + do i = 1, n + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values_f +end module mod_explicit_shape + +subroutine clamp_even_data_points_f(n, X, min_value, max_value) bind(c) + use iso_c_binding, only : c_double, c_int + use mod_explicit_shape, only : clamp_values_f + + implicit none + integer(kind=c_int), intent(in), value :: n + real(kind=c_double), dimension(n), intent(inout) :: X + real(kind=c_double), intent(in), value :: min_value, max_value + + call clamp_values_f(n/2, X(2:n:2), min_value, max_value) +end subroutine clamp_even_data_points_f diff --git a/Checks/PWR087/benchmark/solution.f90 b/Checks/PWR087/benchmark/solution.f90 new file mode 100644 index 00000000..96da8bf9 --- /dev/null +++ b/Checks/PWR087/benchmark/solution.f90 @@ -0,0 +1,36 @@ +! PWR087: Declare array dummy arguments as assumed-shape arrays to favor +! compiler optimizations + +module mod_assumed_shape + implicit none +contains +subroutine clamp_values_improved_f(X, min_value, max_value) + use iso_c_binding, only : c_double, c_int + + implicit none + real(kind=c_double), dimension(:), intent(inout) :: X + real(kind=c_double), intent(in) :: min_value, max_value + + integer(kind=c_int) :: i + + do i = 1, size(X, 1) + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values_improved_f +end module mod_assumed_shape + +subroutine clamp_even_data_points_improved_f(n, X, min_value, max_value) bind(c) + use iso_c_binding, only : c_double, c_int + use mod_assumed_shape, only : clamp_values_improved_f + + implicit none + integer(kind=c_int), intent(in), value :: n + real(kind=c_double), dimension(n), intent(inout) :: X + real(kind=c_double), intent(in), value :: min_value, max_value + + call clamp_values_improved_f(X(2:n:2), min_value, max_value) +end subroutine clamp_even_data_points_improved_f diff --git a/Checks/PWR087/example.f90 b/Checks/PWR087/example.f90 new file mode 100644 index 00000000..f99f4a7b --- /dev/null +++ b/Checks/PWR087/example.f90 @@ -0,0 +1,25 @@ +! PWR087: Declare array dummy arguments as assumed-shape arrays to favor +! compiler optimizations + +module example + implicit none +contains +subroutine clamp_values(n, X, min_value, max_value) + use iso_fortran_env, only: real32 + + implicit none + integer, intent(in) :: n + real(kind=real32), dimension(n), intent(inout) :: X + real(kind=real32), intent(in) :: min_value, max_value + + integer :: i + + do i = 1, n + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values +end module example diff --git a/Checks/PWR087/solution.f90 b/Checks/PWR087/solution.f90 new file mode 100644 index 00000000..5f12eaa3 --- /dev/null +++ b/Checks/PWR087/solution.f90 @@ -0,0 +1,24 @@ +! PWR087: Declare array dummy arguments as assumed-shape arrays to favor +! compiler optimizations + +module solution + implicit none +contains +subroutine clamp_values(X, min_value, max_value) + use iso_fortran_env, only: real32 + + implicit none + real(kind=real32), dimension(:), intent(inout) :: X + real(kind=real32), intent(in) :: min_value, max_value + + integer :: i + + do i = 1, size(X, 1) + if(X(i) < min_value) then + X(i) = min_value + else if(X(i) > max_value) then + X(i) = max_value + end if + end do +end subroutine clamp_values +end module solution diff --git a/README.md b/README.md index e5c24328..66e6580c 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ designed to demonstrate: | [PWR063](Checks/PWR063/) | Avoid using legacy Fortran constructs | correctness, modernization, security | [CWE-477](https://cwe.mitre.org/data/definitions/477.html), [CWE-1075](https://cwe.mitre.org/data/definitions/1075.html), [CWE-1119](https://cwe.mitre.org/data/definitions/1119.html) | [6.27](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.28](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.31](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.54](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.58](https://j3-fortran.org/doc/year/23/23-241.pdf) | | | | ✓ | | | | [PWR068](Checks/PWR068/) | Encapsulate procedures within modules to avoid the risks of calling implicit interfaces | correctness, modernization, security | [CWE-628](https://cwe.mitre.org/data/definitions/628.html) | [6.8](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.9](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.10](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.11](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.32](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.34](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.53](https://j3-fortran.org/doc/year/23/23-241.pdf) | [DCL07-C](https://wiki.sei.cmu.edu/confluence/display/c/DCL07-C.+Include+the+appropriate+type+information+in+function+declarators), [DCL31-C](https://wiki.sei.cmu.edu/confluence/display/c/DCL31-C.+Declare+identifiers+before+using+them), [EXP37-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP37-C.+Call+functions+with+the+correct+number+and+type+of+arguments) | | | ✓ | | | | [PWR069](Checks/PWR069/) | Use the keyword only to explicitly state what to import from a module | correctness, modernization, security | | [6.21](https://j3-fortran.org/doc/year/23/23-241.pdf) | [DCL23-C](https://wiki.sei.cmu.edu/confluence/display/c/DCL23-C.+Guarantee+that+mutually+visible+identifiers+are+unique) | | | ✓ | | ✓[^1] | -| [PWR070](Checks/PWR070/) | Declare array dummy arguments as assumed-shape arrays | correctness, modernization, security, optimization | [CWE-130](https://cwe.mitre.org/data/definitions/130.html) | [6.8](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.9](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.10](https://j3-fortran.org/doc/year/23/23-241.pdf) | [API02-C](https://wiki.sei.cmu.edu/confluence/display/c/API02-C.+Functions+that+read+or+write+to+or+from+an+array+should+take+an+argument+to+specify+the+source+or+target+size) | | | ✓ | | | +| [PWR070](Checks/PWR070/) | Declare array dummy arguments as assumed-shape arrays | correctness, modernization, security | [CWE-130](https://cwe.mitre.org/data/definitions/130.html) | [6.8](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.9](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.10](https://j3-fortran.org/doc/year/23/23-241.pdf) | [API02-C](https://wiki.sei.cmu.edu/confluence/display/c/API02-C.+Functions+that+read+or+write+to+or+from+an+array+should+take+an+argument+to+specify+the+source+or+target+size) | | | ✓ | | | | [PWR071](Checks/PWR071/) | Prefer real(kind=kind_value) for declaring consistent floating types | modernization, portability, security | [CWE-1102](https://cwe.mitre.org/data/definitions/1102.html), [CWE-1339](https://cwe.mitre.org/data/definitions/1339.html) | [6.2](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.4](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.6](https://j3-fortran.org/doc/year/23/23-241.pdf) | [FLP00-C](https://wiki.sei.cmu.edu/confluence/display/c/FLP00-C.+Understand+the+limitations+of+floating-point+numbers) | | | ✓ | | | | [PWR072](Checks/PWR072/) | Explicitly declare the 'save' attribute or split the variable initialization to prevent unintended behavior | correctness, security | [CWE-665](https://cwe.mitre.org/data/definitions/665.html) | [6.54](https://j3-fortran.org/doc/year/23/23-241.pdf) | | | | ✓ | | ✓[^1] | | [PWR073](Checks/PWR073/) | Transform common block into a module for better data encapsulation | correctness, modernization, security | [CWE-1083](https://cwe.mitre.org/data/definitions/1083.html), [CWE-1108](https://cwe.mitre.org/data/definitions/1108.html) | [6.37](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.53](https://j3-fortran.org/doc/year/23/23-241.pdf) | [DCL19-C](https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions) | | | ✓ | | | @@ -99,6 +99,7 @@ designed to demonstrate: | [PWR082](Checks/PWR082/) | Remove unused variables | correctness, security | [CWE-563](https://cwe.mitre.org/data/definitions/563.html) | [6.19](https://j3-fortran.org/doc/year/23/23-241.pdf) | [MSC13-C](https://wiki.sei.cmu.edu/confluence/spaces/c/pages/87152095/MSC13-C.+Detect+and+remove+unused+values) | | ✓ | ✓ | ✓ | | | [PWR083](Checks/PWR083/) | Match the types of dummy and actual arguments in procedure calls | correctness, security | [CWE-628](https://cwe.mitre.org/data/definitions/628.html), [CWE-758](https://cwe.mitre.org/data/definitions/758.html) | [6.11](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.32](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.53](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.56](https://j3-fortran.org/doc/year/23/23-241.pdf) | [EXP37-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP37-C.+Call+functions+with+the+correct+number+and+type+of+arguments), [MSC15-C](https://wiki.sei.cmu.edu/confluence/display/c/MSC15-C.+Do+not+depend+on+undefined+behavior) | | | ✓ | | | | [PWR085](Checks/PWR085/) | Favor iterative implementations over recursion to prevent stack overflows | security | [CWE-674](https://cwe.mitre.org/data/definitions/674.html) | [6.35](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.43](https://j3-fortran.org/doc/year/23/23-241.pdf) | | | ✓ | ✓ | ✓ | | +| [PWR087](Checks/PWR087/) | Declare array dummy arguments as assumed-shape arrays to favor compiler optimizations | optimization | | | | | | ✓ | | | | [PWR088](Checks/PWR088/) | Add missing arguments to procedure calls | correctness, security | [CWE-628](https://cwe.mitre.org/data/definitions/628.html), [CWE-758](https://cwe.mitre.org/data/definitions/758.html) | [6.32](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.56](https://j3-fortran.org/doc/year/23/23-241.pdf) | [EXP37-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP37-C.+Call+functions+with+the+correct+number+and+type+of+arguments), [MSC15-C](https://wiki.sei.cmu.edu/confluence/display/c/MSC15-C.+Do+not+depend+on+undefined+behavior) | | | ✓ | | | | [PWR089](Checks/PWR089/) | Remove unexpected arguments from procedure calls | correctness, security | [CWE-628](https://cwe.mitre.org/data/definitions/628.html), [CWE-758](https://cwe.mitre.org/data/definitions/758.html) | [6.32](https://j3-fortran.org/doc/year/23/23-241.pdf), [6.56](https://j3-fortran.org/doc/year/23/23-241.pdf) | [EXP37-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP37-C.+Call+functions+with+the+correct+number+and+type+of+arguments), [MSC15-C](https://wiki.sei.cmu.edu/confluence/display/c/MSC15-C.+Do+not+depend+on+undefined+behavior) | | | ✓ | | | | [PWD002](Checks/PWD002/) | Unprotected multithreading reduction operation | correctness, security | [CWE-366](https://cwe.mitre.org/data/definitions/366.html), [CWE-820](https://cwe.mitre.org/data/definitions/820.html) | [6.61](https://j3-fortran.org/doc/year/23/23-241.pdf) | [CON07-C](https://wiki.sei.cmu.edu/confluence/display/c/CON07-C.+Ensure+that+compound+operations+on+shared+variables+are+atomic), [CON43-C](https://wiki.sei.cmu.edu/confluence/display/c/CON43-C.+Do+not+allow+data+races+in+multithreaded+code) | | ✓ | ✓ | ✓ | |