Issue 250924.2: DW_OP_mod doesn’t specify which definition of modulo

Author: Ben Woodard
Champion: Mark Wielaard
Date submitted: 2025-09-24
Date revised: 2025-11-24
Date closed: 2025-11-24
Type: Clarification
Status: Accepted
DWARF version: 6

Comparing original with latest. [ Return to the latest version ]

## Background

Evidently, originally DWARF didn’t allow arithmetic operations on
floating point numbers and most uses of the DWARF stack were done with
the assumption that the values being acted upon were addresses and so
the computation was assumed to be acting upon unsigned numbers.
(typed) natural or floating point numbers and most uses of the DWARF
stack were done with the assumption that the values being acted upon
were addresses and so the computation was assumed to be acting upon
unsigned numbers.

At some point, DWARF began to allow the arithmetic operations to work on
At some point, DWARF began to allow the arithmetic operations to work
floating point numbers and several operations were explicitly defined to
work over non-integral values. This led to the paragraph in the current
DWARF working draft that says in section 2.5.2.4 on page 37 lines 24-27:
on (typed) natural or floating point numbers and several operations
were explicitly defined to work over non-integral values. This led to
the paragraph in the current DWARF working draft that says in section
2.5.2.4 on page 37 lines 24-27:

> Operations other than `DW_OP_abs`, `DW_OP_div`,
> `DW_OP_minus`, `DW_OP_mul`, `DW_OP_neg` and `DW_OP_plus`
> require integral types of the operand (either integral base
> type or the generic type). Operations do not cause an
> exception on overflow.

Unlike all the other arithmetic operations this explicitly limits
`DW_OP_mod` to integral base types and the generic type. It lumps
`DW_OP_mod` in with the logical operations. Furthermore, there are
multiple definitions of the modulo operator which vary in how they
handle signed values.

According to the dwarf-discuss archives, this was [raised][tromey] in 2010
and Michael Eager [responded][eager] that `DW_OP_mod` used
the modulo algorithm for unsigned arithmetic. However, this decision was
not recorded in the standard. Since that time, consumers have
implemented different implementations of `DW_OP_mod`.

This proposal seeks to clarify and harmonize the consumer
implementations of the `DW_OP_mod` operator by defining which algorithm to
implementations of the `DW_OP_mod` operator by defining which
use for signed arithmetic as well as define it for floating point numbers.

algorithm to use for signed arithmetic as well as decide whether to
define it for floating point numbers.

## Proposal

Add `DW_OP_mod` to the list of operators which do not require integral
base types by changing:
Rename `DW_OP_mod` to `DW_OP_mod_trunc` and explicitly define the
algorithm used as using truncated division.

> Operations other than `DW_OP_abs`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mul`,
> `DW_OP_neg` and `DW_OP_plus` require integral types of the operand (either
> integral base type or the generic type).
Under 2.5.1.4 Arithmetic and Logical Operations change 5. `DW_OP_mod`
to `DW_OP_mod_trunc`. Add at the end of the paragraph: "Use the
following formula for modulo: *x* `mod_trunc` *y* = *x* − *y* ×
trunc(*x* / *y*)".

To:
Insert 6. `DW_OP_mod_floor` with the same explanation as
`DW_OP_mod_trunc`, but using the formula: "*x* `mod_floor` *y* = *x* − *y*
× floor(*x* / *y*)".

> Operations other than `DW_OP_abs`, `DW_OP_div`, `DW_OP_mod`, `DW_OP_minus`,
> `DW_OP_mul`, `DW_OP_neg` and `DW_OP_plus` require integral types of the
> operand (either integral base type or the generic type).
In Table 7.9: DWARF operation encodings change `DW_OP_mod` to
`DW_OP_mod_trunc`. Add `DW_OP_mod_floor` with constant TBA and no. of
operants zero.

Then append the following sentence to the description of the `DW_OP_mod` operator:
6.4.2 Call Frame Instructions. Add `DW_OP_mod_floor` to the list of
DWARF operators that cannot be used.

Keep the list of operators which do not require integral the
same. `DW_OP_mod_trunc` and `DW_OP_mod_floor` are only defined for
integral types, not floating point.
> The algorithm used to implement modulo shall be the one defined in
> [Knuth][knuth] Volume 1: Fundamental Algorithms, Section 1.2.4.


## Alternative proposals

1. Explicitly state in the standard that `DW_OP_mod` is only defined for
unsigned integral arithmetic. This effectively standardizes the 2010 [ruling][eager].

2. Pick any algorithm for modulo that works for signed as well unsigned
arithmetic and specify that `DW_OP_mod` shall follow it. The current
GDB implementation follows [Knuth][knuth] 1.2.4 for signed and unsigned integral
arithmetic but excludes the algorithm for reals and floating point numbers.


## References

From [Knuth][knuth] Section 1.2.4:

> If *x* and *y* are any real numbers, we define the following binary operation:
> 
> > *x* mod *y* = *x* − *y* × floor(*x* / *y*), if *y* ≠ 0; *x* mod 0 = *x*.


[tromey]: https://lists.dwarfstd.org/pipermail/dwarf-discuss/2010-January/000805.html
[eager]: https://lists.dwarfstd.org/pipermail/dwarf-discuss/2010-January/000806.html
[knuth]: https://www-cs-faculty.stanford.edu/~knuth/taocp.html

---

2025-10-27: Identified the following options:

- Define `DW_OP_mod` for unsigned arithmetic only.
- Pick one definition to support signed arithmetic
  (see Wikipedia article on [Modulo][wiki]):
    - Floored (Knuth, typically called modulo)
    - Truncated (often called remainder)
    - Euclidean (always non-negative, uncommon)
    - Rounded (mostly used only for floating-point remainder)
- Define `DW_OP_mod` to use floored division;
  add `DW_OP_rem` using truncated division.
- Make it language/target dependent [ruled out by consensus].

Orthogonal:

- Should it/they be defined for floating-point?
- Should operations on the generic type be unsigned?

[wiki]: https://en.wikipedia.org/wiki/Modulo

2025-11-24: [Update][diff1] after vote on naming and proposal for other issues.

- Update background to mention this isn't just about floating point.
- Rename `DW_OP_mod` to `DW_OP_mod_trunc` (but keep constant value)
- Define `DW_OP_mod_trunc` to use truncated division
- Add `DW_OP_mod_floor`, defined using floored division
- Explicitly disallow `DW_OP_mod_floor` in CFI
- Don't define for zero nominator (like division, expr just errors)
- Don't change the operators that require integral values
  (won't support floating point for modulo)

2025-11-24: Accepted.