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

            Bug ID: 109086
           Summary: Bug of builtin_strcmp in the case of using the adddi3
                    instruction patterns
           Product: gcc
           Version: 13.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: liwei at loongson dot cn
  Target Milestone: ---

Created attachment 54631
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54631&action=edit
cause builtin_strcmp bug file

When we try to force add<mode>3 insn patterns only match DI mode for some
reason (this is safe because Loongarch defines the macro PROMOTE_MODE to
promote all modes narrower than BITS_PER_WORD to BITS_PER_WORD), it fails in
the following test case.

extern const char* deal(const char* filename);
const char* foo (filename) 
    const char *filename;
{
    if (filename == NULL || !strcmp (filename, "-"))
        filename = ""; 
    return deal(filename); 
}

We use glibc's script build-many-glibcs.py to cross build loongarch64 gcc, and
use -O2 command to compile above test case.

Part of the assembly code is as follows:

.LFB0 = .
    .cfi_startproc
    beqz    $r4,.L5
    ld.bu   $r12,$r4,0
    addi.w  $r12,$r12,-45
    beqz    $r12,.L7
    slli.w  $r12,$r13,0
    bnez    $r12,.L2
...

The r12 register uses the uninitialized r13 register, which makes subsequent
bnez insn wrong.

Through gdb debugging we found that the problem occurs in
builtins.cc:inline_string_cmp, below is the problem code.

rtx result = target ? target : gen_reg_rtx (mode);
...
for (unsigned HOST_WIDE_INT i = 0; i < length; i++) 
{
...
op0 = convert_modes (mode, unit_mode, op0, 1);
op1 = convert_modes (mode, unit_mode, op1, 1);
result = expand_simple_binop (mode, MINUS, op0, op1,
               result, 1, OPTAB_WIDEN);
...
}

The result is empty at the beginning, and a new temporary register is used to
save the result of the first strcmp comparison, there is no problem in the
first loop.
>From the second loop, the expand_simple_binop function actually calls the
expand_binop function. Since there is no addsi3 insn pattern, gcc will promote
the machine mode of the two operands op0 and op1 to DI, then match it to
adddi3, the result is stored in the temporary register and returned (because
the mode is MODE_INT and loongarch supports TRUNCATION). The previous result is
discarded, which resulting in error.

Attached are the diff file used to reproduce the bugs on loongarch and the
corresponding fix patches given.

Reply via email to