Избегайте дополнительной нагрузки после вызова библиотеки в оптимизированном коде - PullRequest
0 голосов
/ 12 декабря 2011

Реализация структуры данных с двумя функциональными указателями, key_eq и key_hash. Когда эти указатели на функции устанавливаются только один раз и никогда не изменяются, я бы хотел, чтобы gcc компилировался по адресу функции напрямую, а не загружал элемент struct, однако один вызов puts("") нарушит постоянное распространение gcc (правильный термин?).

Ниже приведен небольшой фрагмент кода АСМ. Видно, что поле key_hash сохраняется, мы называем libc puts, а затем загружается key_hash. Если puts удалено, константа распространяется правильно. Это неизбежно?

    lis 9,hasheq_string@ha   # tmp174,                                       
    la 0,hasheq_string@l(9)  # tmp173,, tmp174                               
    stw 3,16(1)      # h.flags,                                              
    lis 9,hashf_string@ha    # tmp176,                                       
    lis 3,.LC0@ha    # tmp178,                                               
    stw 0,36(1)      # h.key_eq, tmp173                                      
    la 0,hashf_string@l(9)   # tmp175,, tmp176                               
    la 3,.LC0@l(3)   #,, tmp178                                              
    stw 0,40(1)      # h.key_hash, tmp175                                    
    bl puts  #                                                               
    lwz 0,40(1)      # h.key_hash, h.key_hash                                
    mr 3,31  #, tmp164                                                       
    stw 31,32(1)     # h._key, tmp164                                        
    mtctr 0  #, h.key_hash                                                   
    bctrl    #   

Прошу прощения за то, что у меня нет тестового набора C, но мне трудно его воспроизвести, но короткая трехстрочная последовательность "store, blетки, load" приводит к вопросу, разве это невозможно? вокруг?

1 Ответ

1 голос
/ 12 декабря 2011

Возможно, что GCC консервативно предполагает, что вызов puts может читать / записывать память, поэтому значение в key_hash может понадобиться вызываемой функции и может отличаться до и после вызова.

Этот код:

struct S
{
  int f;
};

void bar ();

int
foo (struct S *s)
{
  s->f = 314;
  bar ();
  return s->f + 2;
}

создает последовательность "подписи":

foo:
    mflr 0
    stwu 1,-32(1)
    stw 29,20(1)
    mr 29,3
    stw 0,36(1)
    li 0,314
    stw 0,0(3)  ;;
    bl bar      ;; here we go
    lwz 3,0(29) ;;
    lwz 0,36(1)
    addi 3,3,2
    lwz 29,20(1)
    mtlr 0
    addi 1,1,32
    blr

Однако с небольшой модификацией (ручная скалярная замена агрегатов?):

struct S
{
  int f;
};

void bar ();

int
foo (struct S *s)
{
  int i;

  s->f = i = 314;
  bar ();
  return i + 2;
}

получается желаемый результат:

foo:
    mflr 0
    stwu 1,-16(1)
    stw 0,20(1)
    li 0,314
    stw 0,0(3)
    bl bar
    lwz 0,20(1)
    li 3,316    ;; constant propagated and folded
    addi 1,1,16
    mtlr 0
    blr
...