Skip to content

Commit fe60670

Browse files
author
Rui Marques
committed
Split the quality part of PWR0{28,30} to PWR086
1 parent 6e749cc commit fe60670

8 files changed

Lines changed: 150 additions & 4 deletions

File tree

Benchmark/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ add_benchmark(PWR080)
2323
add_benchmark(PWR081)
2424
add_benchmark(PWR082)
2525
add_benchmark(PWR083)
26+
add_benchmark(PWR086)
2627
add_benchmark(PWR087)

Benchmark/src/PWR086.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include "Benchmark.h"
2+
3+
// Forward-declare the functions to benchmark
4+
extern "C" {
5+
void pointer_increment_example(float *a, float *b, float *c, unsigned size,
6+
unsigned inc);
7+
void pointer_increment_improved(float *a, float *b, float *c, unsigned size,
8+
unsigned inc);
9+
}
10+
11+
// Size adjusted to fit execution on micro-seconds
12+
constexpr unsigned N_VEC = 1024 * 1024;
13+
constexpr unsigned INC = 1;
14+
constexpr unsigned N_MAT = 128;
15+
16+
#if OCB_ENABLE_C
17+
18+
static void CPointerIncrementExampleBench(benchmark::State &state) {
19+
auto a = OpenCatalog::CreateRandomVector<float>(N_VEC);
20+
auto b = OpenCatalog::CreateRandomVector<float>(N_VEC);
21+
auto c = OpenCatalog::CreateZeroVector<float>(1);
22+
// Point to the last element so that b[-i*inc] stays in bounds
23+
float *bEnd = b.data() + N_VEC - 1;
24+
for (auto _ : state) {
25+
pointer_increment_example(a.data(), bEnd, c.data(), N_VEC, INC);
26+
benchmark::DoNotOptimize(c);
27+
}
28+
}
29+
30+
static void CPointerIncrementImprovedBench(benchmark::State &state) {
31+
auto a = OpenCatalog::CreateRandomVector<float>(N_VEC);
32+
auto b = OpenCatalog::CreateRandomVector<float>(N_VEC);
33+
auto c = OpenCatalog::CreateZeroVector<float>(1);
34+
// Point to the last element so that b[-i*inc] stays in bounds
35+
float *bEnd = b.data() + N_VEC - 1;
36+
for (auto _ : state) {
37+
pointer_increment_improved(a.data(), bEnd, c.data(), N_VEC, INC);
38+
benchmark::DoNotOptimize(c);
39+
}
40+
}
41+
42+
OC_BENCHMARK("PWR086 C Pointer Increment Example",
43+
CPointerIncrementExampleBench);
44+
OC_BENCHMARK("PWR086 C Pointer Increment Improved",
45+
CPointerIncrementImprovedBench);
46+
47+
#endif

Checks/PWR028/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void example(float *a, float *b, float *c, unsigned size, unsigned inc) {
6363
> less error-prone than pointer-based notation. This is especially relevant
6464
> when accessing multi-dimensional arrays with a single pointer `*`, where
6565
> offsets must be manually computed by multiplying indices with the
66-
> corresponding dimensions.
66+
> corresponding dimensions. See [PWR086](../PWR086/README.md)
6767
6868
### Related resources
6969

Checks/PWR030/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ for (int i = 0; i < size; i++) {
6969
> less error-prone than pointer-based notation. This is especially relevant
7070
> when accessing multi-dimensional arrays with a single pointer `*`, where
7171
> offsets must be manually computed by multiplying indices with the
72-
> corresponding dimensions.
72+
> corresponding dimensions. See [PWR086](../PWR086/README.md)
7373
7474
### References
7575

Checks/PWR086/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# PWR086: Prefer array-based notation over pointer-based notation for readability
2+
3+
### Issue
4+
5+
Using pointer increments or pointer assignments to access array elements reduces
6+
code readability and is more error-prone compared to equivalent array-based
7+
(index-based) notation.
8+
9+
### Actions
10+
11+
Replace pointer-based array access patterns with array-based (index-based)
12+
notation.
13+
14+
### Relevance
15+
16+
Pointer-based notation for accessing array elements is a common pattern in C and
17+
C++ code. While functionally equivalent to array-based notation, pointer-based
18+
access introduces unnecessary complexity that harms code quality:
19+
20+
- **Error-proneness**: pointer arithmetic is a frequent source of off-by-one
21+
errors and out-of-bounds accesses, especially when accessing multi-dimensional
22+
arrays with a single pointer `*`, where offsets must be manually computed by
23+
multiplying indices with the corresponding dimensions. Array-based notation
24+
makes the intent explicit and reduces the chance of such mistakes.
25+
- **Readability**: understanding which element of the array is being accessed
26+
requires mentally tracking the pointer's value across modifications in the
27+
control flow. With array-based notation, the accessed element is immediately
28+
clear from the index expression.
29+
- **Maintainability**: changing access regions is significantly harder when
30+
pointer arithmetic must be updated in tandem. Array-based notation keeps the
31+
indexing logic self-contained and localized.
32+
33+
### Code example
34+
35+
The following loop uses a pointer increment to walk through the elements of
36+
array `b`:
37+
38+
```c
39+
void example(float *a, float *b, float *c, unsigned size, unsigned inc) {
40+
float *bTemp1 = b;
41+
for (unsigned i = 0; i < size; i++) {
42+
c[0] += (a[i] * bTemp1[0]);
43+
bTemp1 -= inc;
44+
}
45+
}
46+
```
47+
48+
The pointer `bTemp1` is decremented by `inc` on every iteration, making it
49+
difficult to see at a glance which element of `b` is accessed in each iteration.
50+
Replacing the pointer notation with array indexing makes the access pattern
51+
explicit:
52+
53+
```c
54+
void example(float *a, float *b, float *c, unsigned size, unsigned inc) {
55+
for (unsigned i = 0; i < size; i++) {
56+
c[0] += (a[i] * b[-i * inc]);
57+
}
58+
}
59+
```
60+
61+
Now the relationship between the loop variable `i` and the accessed element of
62+
`b` is immediately visible.
63+
64+
> [!TIP]
65+
> Array-based notation also enables compiler optimizations such as automatic
66+
> vectorization and loop interchange. See [PWR028](../PWR028/README.md) and
67+
> [PWR030](../PWR030/README.md) for performance-focused checks covering the
68+
> same code patterns.
69+
70+
### Related resources
71+
72+
* [PWR086 examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR086/)
73+
* [PWR028: Remove pointer increment preventing performance optimization](../PWR028/README.md)
74+
* [PWR030: Remove pointer assignment preventing performance optimization for perfectly nested loops](../PWR030/README.md)
75+
76+
### References
77+
* [CWE-468: Incorrect Pointer Scaling](https://cwe.mitre.org/data/definitions/468.html)

Checks/PWR086/example.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// PWR086: Prefer array-based notation over pointer-based notation for
2+
// readability
3+
4+
void pointer_increment_example(float *a, float *b, float *c, unsigned size,
5+
unsigned inc) {
6+
float *bTemp1 = b;
7+
for (unsigned i = 0; i < size; i++) {
8+
c[0] += (a[i] * bTemp1[0]);
9+
bTemp1 -= inc;
10+
}
11+
}

Checks/PWR086/solution.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// PWR086: Prefer array-based notation over pointer-based notation for
2+
// readability
3+
4+
void pointer_increment_improved(float *a, float *b, float *c, unsigned size,
5+
unsigned inc) {
6+
for (unsigned i = 0; i < size; i++) {
7+
c[0] += (a[i] * b[-(int)(i * inc)]);
8+
}
9+
}

0 commit comments

Comments
 (0)