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.