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

--- Comment #1 from migraineman33 at gmail dot com ---
---

Following up on this report with a precise root cause, a one-line fix,
and field validation.

ROOT CAUSE

In gcc/config/pdp11/pdp11.md, the `lshr<mode>3` define_expand's QImode
branch emits the shift without negating the count:

    if (<QHSint:e_mname> == E_QImode)
      {
        r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode,
operands[1]));
        emit_insn (gen_aslhi_op (r, r, operands[2]));
        emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
      }

`aslhi_op` maps to the PDP-11 ASH instruction, whose count is signed:
positive shifts left, negative shifts right. A logical right shift of a
QImode value therefore compiles to a LEFT shift — silent wrong code, no
diagnostic. Compare the `ashr<mode>3` expander immediately above, which
correctly performs `operands[2] = negate_rtx (HImode, operands[2]);`
before the same QImode sequence; `lshr<mode>3`'s non-QImode arm also
accounts for direction (via the 1-bit lshiftrt + adjusted count). Only
the QImode arm of lshr<mode>3 is missing the negation.

The defect is present in releases at least through 13.3.0 and is still
present in current master (checked gcc-mirror HEAD as of 2026-07-04).

The affected path is taken when pdp11_expand_shift() declines the
small-constant sequence — i.e. variable shift counts (and large
constants), e.g.:

    unsigned char f (unsigned char x, int n) { return x >> n; }

which emits `ash` with the positive count in place of the negated one.

FIX (one line, mirrors ashr<mode>3):

    --- a/gcc/config/pdp11/pdp11.md
    +++ b/gcc/config/pdp11/pdp11.md
    @@ (define_expand "lshr<mode>3") @@
           if (<QHSint:e_mname> == E_QImode)
             {
               r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode,
operands[1]));
    +          operands[2] = negate_rtx (HImode, operands[2]);
               emit_insn (gen_aslhi_op (r, r, operands[2]));
               emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r,
0)));
             }

FIELD VALIDATION

This is not a synthetic finding. With the one-line patch applied to
GCC 13.3.0 (pdp11-aout), we have built a complete operating system —
the Fuzix 0.4.1 kernel, C library, and a 35-program userland — and run
it multi-process with MMU address separation and swap on PDP-11
hardware (a cycle-faithful FPGA recreation of an 11/20+11/40-class
MMU on a Lattice iCE40-UP5K), interactively verified at the console
on 2026-07-04. Before the patch, byte right-shifts in the kernel's
tty/device paths produced corrupt results and required source-level
workarounds (word-widening reads); with the patch, the system is fully
operational and no regressions have been observed anywhere in the
kernel or userland.
  • [Bug target/125058] pdp11: lsh... migraineman33 at gmail dot com via Gcc-bugs

Reply via email to