https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126285

            Bug ID: 126285
           Summary: gcobol: USAGE COMP-5 COMPUTE not lowered to host
                    integer arithmetic
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: cobol
          Assignee: unassigned at gcc dot gnu.org
          Reporter: peeterjoot at protonmail dot com
  Target Milestone: ---

Created attachment 65063
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65063&action=edit
comp5-compute-via-runtime.cob mentioned in the report.

# Summary

At `-O2`, `COMPUTE` / `MULTIPLY` / `ADD` / `SUBTRACT` / `DIVIDE` on
`USAGE COMP-5` (binary integer) operands are implemented entirely as calls into
`libgcobol` field-arithmetic helpers (`__gg__multiplyf2`,
`__gg__add_fixed_phase1`, `__gg__subtractf2_fixed_phase1`,
`__gg__fixed_phase2_assign_to_c`, `__gg__move`, plus per-op
`__gg__initialize_variable_clean` of intermediate stack fields and
`__gg__process_compute_error`).  No host `mul` / `add` / `sdiv` appears in the
hot path.

For a tight 5 000 000-iteration COMP-5 loop this is about **250× slower** than
the equivalent C/C++ `-O2 -fno-tree-vectorize` loop (or another COBOL compiler
that lowers COMP-5 to native integers).  Even the trivial statement

```cobol
COMPUTE WS-X = WS-X + 1
```

with `WS-X PIC S9(9) USAGE COMP-5` expands to
`add_fixed_phase1` → `fixed_phase2_assign_to_c` → `move` →
`process_compute_error`.

# Environment

- Compiler: `gcobol` from GCC trunk (`/opt/gcc-trunk-20260710`, 2026-07-10)
- Platform: Linux aarch64 (also expected on x86-64)
- Options: `-O2 -ffixed-form -main`

# Reproducer

`comp5-compute-via-runtime.cob` (this directory).

```
gcobol -O2 -ffixed-form -main -o slowcomp5 \
  gcobol-bugs/comp5-compute-via-runtime.cob
time ./slowcomp5
objdump -d slowcomp5 --disassemble=slowcomp5 | grep -E '__gg__|mul |add '
```

Pure C++ baseline (same arithmetic, no COBOL runtime) is
`comp5-compute-via-runtime.cpp`:

```
g++ -O2 -fno-tree-vectorize -std=c++20 -o slowcomp5-cpp \
  gcobol-bugs/comp5-compute-via-runtime.cpp
time ./slowcomp5-cpp
```

`-fno-tree-vectorize` keeps the loop scalar so the timing is an
apples-to-apples
compare with gcobol (whose COMP-5 `COMPUTE` path is scalar `libgcobol` calls,
not
SIMD).  Plain `g++ -O2` vectorizes this loop 4-wide, which would overstate the
native-integer advantage.

Equivalent C for the timing baseline (same flag):

```c
#include <stdio.h>
#include <stdint.h>
int main(void) {
  int32_t n = 5000000;
  int64_t x = 0;
  for (int32_t i = 1; i <= n; ++i) {
    int32_t a = 2 * i - 1;
    int32_t b = i * a;
    x = x + b;
  }
  printf("%lld\n", (long long)x);
  return 0;
}
```

```
gcc -O2 -fno-tree-vectorize -o slowcomp5-c slowcomp5.c
```

# Observed (gcobol -O2)

Timing (5e6 iterations, aarch64):

| build | wall time |
|---|---|
| gcobol `-O2` | ~0.76 s |
| `g++ -O2 -fno-tree-vectorize` C++ baseline | ~0.002 s |
| ratio | ~**380×** |

`objdump` of `slowcomp5`: every arithmetic step in the loop is a PLT call, e.g.

```
bl  __gg__initialize_variable_clean
bl  __gg__multiplyf2
bl  __gg__initialize_variable_clean
bl  __gg__subtractf2_fixed_phase1
bl  __gg__fixed_phase2_assign_to_c
bl  __gg__move
bl  __gg__process_compute_error
...
bl  __gg__multiplyf2
...
bl  __gg__add_fixed_phase1
...
```

There is **no** host `mul` / `madd` / integer `add` for the COMPUTE bodies.
`-fdump-tree-optimized` shows the same call sequence with descriptor setup into
`cbl_field_ptr_t` arrays before each helper.

Numeric result is correct (`12237243672096`); this is a performance / codegen
issue, not a wrong-answer bug for this program.

# Expected

For `USAGE COMP-5` / `BINARY` items with no `ON SIZE ERROR`, scale (`V`), or
decimal intermediate, `-O2` should lower simple `COMPUTE` expressions to host
integer operations (as the C baseline does), rather than routing every operator
through the general field runtime.

# Additional observation (compound COMPUTE)

In a larger program (batched pi-spigot,
`CALCPI/COBOL/spigot/calcpi-spigot-batch.cob`),
compound expressions such as

```cobol
COMPUTE LS-X = LS-B * LK-A(A-IDX) + LS-CARRY
```

with all binary (`COMP-5`) operands also introduce **`float:128` intermediate
stack fields** and call `__gg__add_float_phase1` /
`__gg__float_phase2_assign_to_c`.  That path is not required for the minimal
reproducer above (fixed-phase helpers suffice to show the slowdown), but it
amplifies the cost further in real numerical kernels (~30–50× vs a native
COMP-5 lowering of the same source).

# Related

Found while comparing gcobol vs a native COMP-5 lowering of a toy pi
calculation program
`CALCPI/COBOL/spigot/calcpi-spigot-batch.cob` (same algorithm, same digit
count).
  • [Bug cobol/126285] New: gcob... peeterjoot at protonmail dot com via Gcc-bugs

Reply via email to