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

            Bug ID: 91347
           Summary: [7,8,9 Regression] pointer_string in linux vsprintf.c
                    is miscompiled when sibling calls are optimized
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: danglin at gcc dot gnu.org
                CC: deller at gmx dot de, svens at stackframe dot org
  Target Milestone: ---
              Host: hppa-unknown-linux-gnu
            Target: hppa-unknown-linux-gnu
             Build: hppa-unknown-linux-gnu

Created attachment 46669
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46669&action=edit
Preproccessed source

Sven Schnelle wrote:

I wasn't able to write a reproducer so far, but the problem is in
lib/vsprintf.c
pointer_string():

char *pointer_string(char *buf, char *end,
                const void *ptr,
                struct printf_spec spec)
{
        spec.base = 16;
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
                spec.field_width = 2 * sizeof(ptr);
                spec.flags |= ZEROPAD;
        }

        return number(buf, end, (unsigned long int)ptr, spec);
}

this generates:

00003a34 <pointer_string>:
{
    3a34:       4b dc 3f 91     ldw -38(sp),ret0
    3a38:       6b c2 3f d9     stw rp,-14(sp)
    3a3c:       d3 9c 1f e8     extrw,s ret0,31,24,ret0
        if (spec.field_width == -1) {
    3a40:       93 80 37 ff     cmpiclr,<> -1,ret0,r0
    3a44:       34 1c 00 10     ldi 8,ret0
        return number(buf, end, (unsigned long int)ptr, spec);
    3a48:       4b d3 3f 91     ldw -38(sp),r19
    3a4c:       34 17 00 00     ldi 0,r23
}
    3a50:       4b c2 3f d9     ldw -14(sp),rp
        return number(buf, end, (unsigned long int)ptr, spec);
    3a54:       d6 7c 0c 08     depw ret0,31,24,r19
    3a58:       6b d3 3f 91     stw r19,-38(sp)
    3a5c:       e8 1e 0d bd     b,l 1140 <number>,r0
    3a60:       08 00 02 40     nop
    3a64:       08 00 02 40     nop

I don't see where spec.base get's assigned, and even the source code line is
omitted in the objdump -S output.

The problem can be duplicated by compiling with -O2 or -Os.

The type of spec is:

struct printf_spec {
 unsigned int type:8;
 signed int field_width:24;
 unsigned int flags:8;
 unsigned int base:8;
 signed int precision:16;
} __attribute__((__packed__));

Reviewing the RTL dumps, I see that the assignment of spec.base is dropped in
the dse1 pass.  In vsprintf.i.258r.cse2, we have:

(insn 19 15 20 2 (set (reg:QI 113)
        (const_int 16 [0x10]))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":675 65 {*pa.md:3045}
     (nil))
(insn 20 19 63 2 (set (mem/j/c:QI (plus:SI (reg/f:SI 107)
                (const_int 5 [0x5])) [241 spec.base+0 S1 A8])
        (reg:QI 113))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":675 65 {*pa.md:3045}
     (expr_list:REG_DEAD (reg:QI 113)
        (expr_list:REG_DEAD (reg/f:SI 107)
            (nil))))

This changes in vsprintf.i.259r.dse1 to:

(insn 19 15 21 2 (set (reg:QI 113)
        (const_int 16 [0x10]))
"/home/svens/linux-kernel/parisc-linux/src/lib/vs
printf.c":675 65 {*pa.md:3045}
     (nil))
(jump_insn 21 19 22 2 (set (pc)
        (if_then_else (eq (reg:SI 98 [ spec$field_width ])
                (const_int -1 [0xffffffffffffffff]))
            (label_ref 27)
            (pc)))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":67
7 30 {*pa.md:1413}
     (int_list:REG_BR_PROB 365072228 (nil))
 -> 27)

The DSE processing for insn 20 is:

**scanning insn=20
  mem: (plus:SI (reg/f:SI 107)
    (const_int 5 [0x5]))

   after canon_rtx address: (plus:SI (reg/f:SI 3 %r3)
    (const_int -51 [0xffffffffffffffcd]))
  gid=0 offset=-51
 processing const base store gid=0[-51..-50)
mems_found = 1, cannot_delete = false

starting to process insn 20
  v:  1, 2
i = -51, index = 1
deferring deletion of insn with uid = 20.

Gcc-6 doesn't drop the spec.base assignment.  Dropping the assignment causes
calls to pointer_string to be output in decimal.

Reply via email to