Почему GCC генерирует разные коды операций для умножения на основе значения константы? - программирование
Подтвердить что ты не робот

Почему GCC генерирует разные коды операций для умножения на основе значения константы?

Я играл с дизассемблером GCC на gcc.godbolt.org, и я заметил, что стартовая версия GCC 4.6 компилирует размножение по-разному. Я имею следующие две функции:

unsigned m126(unsigned i)
{
    return i * 126;
}

unsigned m131(unsigned i)
{
    return i * 131;
}

m126 компилируется в:

mov eax, edi
mov edx, 126
imul eax, edx
ret

И m131 скомпилируется в:

imul eax, edi, 131
ret

Почему разница? GCC 4.5 генерирует один и тот же код операции в обоих случаях.

Ссылка на фактический пример в GCC Explorer.

4b9b3361

Ответ 1

Нашел это в gcc/config/i386/i386.md (см. комментарий сверху):

;; imul $8/16bit_imm, regmem, reg is vector decoded.
;; Convert it into imul reg, reg
;; It would be better to force assembler to encode instruction using long
;; immediate, but there is apparently no way to do so.
(define_peephole2
  [(parallel [(set (match_operand:SWI248 0 "register_operand")
           (mult:SWI248
            (match_operand:SWI248 1 "nonimmediate_operand")
            (match_operand:SWI248 2 "const_int_operand")))
          (clobber (reg:CC FLAGS_REG))])
   (match_scratch:SWI248 3 "r")]
  "TARGET_SLOW_IMUL_IMM8 && optimize_insn_for_speed_p ()
   && satisfies_constraint_K (operands[2])"
  [(set (match_dup 3) (match_dup 2))
   (parallel [(set (match_dup 0) (mult:SWI248 (match_dup 0) (match_dup 3)))
          (clobber (reg:CC FLAGS_REG))])]
{
  if (!rtx_equal_p (operands[0], operands[1]))
    emit_move_insn (operands[0], operands[1]);
})

Похоже, что это имеет какое-то отношение к расшифровке команд (извините, что я не эксперт)