Кресты / Говнокод #26389 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
// https://www.linux.org.ru/forum/development/15496357

// Нужен нормальный способ сказать компилятору что type aliasing невозможен на некотором участке кода. Минимальный пример:

template<typename T> struct f final {
	void bad(T v) noexcept { while (b != e) *b++=v; }
	void good(T v) noexcept {
		auto tb(b), te(e);
		while (tb != te) *tb++=v;
		b=tb;
		e=te;
	}

	T* b, * e;
};
template struct f<char>;
/*
Выхлоп gcc-8:

$ g++ -xc++ -std=c++14 -pedantic-errors -Os -c -of.o f.cc
$ objdump -Cd f.o
f.o:     file format elf64-x86-64


Disassembly of section .text._ZN1fIcE3badEc:

0000000000000000 <f<char>::bad(char)>:
   0:	48 8b 07             	mov    (%rdi),%rax
   3:	48 3b 47 08          	cmp    0x8(%rdi),%rax
   7:	74 0c                	je     15 <f<char>::bad(char)+0x15>
   9:	48 8d 50 01          	lea    0x1(%rax),%rdx
   d:	48 89 17             	mov    %rdx,(%rdi)
  10:	40 88 30             	mov    %sil,(%rax)
  13:	eb eb                	jmp    0 <f<char>::bad(char)>
  15:	c3                   	retq   

Disassembly of section .text._ZN1fIcE4goodEc:

0000000000000000 <f<char>::good(char)>:
   0:	48 8b 07             	mov    (%rdi),%rax
   3:	48 8b 57 08          	mov    0x8(%rdi),%rdx
   7:	48 39 d0             	cmp    %rdx,%rax
   a:	74 09                	je     15 <f<char>::good(char)+0x15>
   c:	48 ff c0             	inc    %rax
   f:	40 88 70 ff          	mov    %sil,-0x1(%rax)
  13:	eb f2                	jmp    7 <f<char>::good(char)+0x7>
  15:	48 89 07             	mov    %rax,(%rdi)
  18:	48 89 47 08          	mov    %rax,0x8(%rdi)
  1c:	c3                   	retq
*/

f<char>::bad(char)+0, f<char>::bad(char)+3 и f<char>::bad(char)+d - три раза за итерацию лезет в память. Разумеется, подобный код сливает в тестах производительности. Есть решение лучше, чем локальные переменные заводить каждый раз?

Запостил: j123123 j123123, (Updated )

Комментарии (41) RSS

    • while (b != e) *b++=v;

      Н-н-н-нооо позвольте, где здесь С++, j123123?!это же чистая сишка.
      Ответить
      • Тут какие-то анскиллушные темплейты и структуры с функциями - в Си такого нет.
        Ответить
        • Это именно сишный паттерн, дрочить указатели в цикле while
          while (*s++ = *t++);
          Ответить
          • Если написать нормальную сишную функцию в этом говне:
            template<typename T> struct f final {
                void very_good(T v) noexcept { my_f(b,e,v); }
            
                void my_f(T* b, T* e, T v)
                {
                    while (b != e) *b++=v;
                }
            
                T* b, * e;
            };
            template struct f<char>;


            то тогда GCC соптимизирует в memset:
            f<char>::very_good(char):
                    movq    8(%rdi), %rdx
                    movq    (%rdi), %rdi
                    cmpq    %rdi, %rdx
                    je      .L1
                    subq    %rdi, %rdx
                    movsbl  %sil, %esi
                    jmp     memset
            .L1:
                    ret


            Именно поэтому я за нормальные функции, а не всякое говно
            Ответить
            • Ну ты же локалок добавил и изменение b не закоммитил в мембер. Код не эквивалентный вообще.
              Ответить
                • Ну можно проверить чтоб вот в диапазон где продрачивается цикл while (b != e) *b++=v; не попадает диапазон адресов самой этой структуры, и тогда заоптимизировать на основе этого.
                  Ответить
              • Ну тогда вот так
                void my_f(T* b_, T* e, T v)
                {
                    while (b_ != e) *b_++=v;
                    b = e;
                }
                Ответить
                • Вы поймите, компилятор делает то что ему сказали.

                  В случае bad ему явно говорят: инкременти указатель в структуре на каждой итерации.

                  В случае good ему явно говорят: скопируй себе указатель, поитерируй и поменяй его в конце цикла.

                  Понимаю что в царском мире, где у процессора одно ядро, а потоки не нужны, оба случая кажутся эквивалентными.

                  Однако это не так, ибо в многопоточном коде различие СУЩЕСТВЕННОЕ.
                  Ответить
                  • Компилятору насрать на потоки и прерывания если ты не юзаешь атомики или volatile. Поменяй на что-нибудь кроме char и он перестанет хуйнёй страдать.

                    Он именно в своём единственном треде ссыт затереть b или e во время записи в *b.
                    Ответить
                      • Если говношаблон
                        template<typename T> struct f final {
                        	void bad(T v) noexcept { while (b != e) *b++=v; }
                        	void good(T v) noexcept {
                        		auto tb(b), te(e);
                        		while (tb != te) *tb++=v;
                        		b=tb;
                        		e=te;
                        	}
                        
                        	T* b, * e;
                        };


                        специализировать типом int, крестоговнокомпилятор не будет предполагать что он перепишет хуйней "while (b != e) *b++=v;" хуйню "T* b, * e;" в этой говноструктуре
                        Ответить
                        • Да причём тут шаблон. В сишке с глобалками или полями структуры под b и e у тебя та же самая ерунда будет.
                          Ответить
                          • А я и не спорю. Шаблон тут оттого, что он в исходном говнокоде присутствует.
                            Ответить
    • Ну по-стандарту указатель на сhar может указывать на любую хуйню и переписывать ее. Если там char, крестоговняный компилятор предполагает что хуйня "*b++=v;" может переписать указатели "T* b, * e;" в самой структуре и поэтому дрочит память
      Ответить
        • Вообще char — это какой-то страшный тип. Он не signed char и не unsigned char. Он особенный.
          Ответить
          • Факт.

            6.5 Expressions
            7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types: 
            (The intent of this list is to specify those circumstances in which an object may or may not be aliased. )
            
            *    a type compatible with the effective type of the object,
            *    a qualified version of a type compatible with the effective type of the object,
            *    a type that is the signed or unsigned type corresponding to the effective type of the object,
            *    a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
            *    an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
            *    a character type. 
            Ответить
      • Пиздец.

        Но на ЛОРе правильно сказали. Это сишка.

        >Твой пример - это не код на с++, это си-код.
        
        >std::fill(b, e, v);

        Человек пытался писать на крестах как на сишке. Ну и получил. Ещё по-божески.
        Ответить
        • > std::fill

          // Specialization: for char types we can use memset

          (и это не шутка, там реально специализация через мемсет)
          Ответить
        • Мой критерий прост: если код компилируется крестокомпилятором - значит это код на C++. А используется или нет какая-то std::kokoko дрисня - дело десятое
          Ответить
          • Так борманд правильно говорит: мы можем такое же наговнячить в сишке.

            И оно будет так же криво оптимизироваться.

            Арифметика указателей, структуры, сhar. Кресты здесь причём?
            Ответить
            • Исходный код по ссылке на ЛОРе был на крестах - поэтому код был запощен как говнокод на крестах.

              Если б я этот код запостил как код на Си, мне б сказали что тут template<typename T> а в Си такого нет.
              Ответить
              • Но вы упорно продолжаете обсирать кресты, хотя в божественной сишке точно такой же изъян, если обращаться к структуре напрямую.

                template тут не при чём.
                Ответить
                • https://govnokod.ru/23287#comment389547

                  > Тоесть, смотрите, как ведет себя настоящий, состоявшийся, знающий себе цену программист? А он ведет себя очень просто: плюсы - говно, но и си - говно, кричит он громко, ничуть не смущаясь подходящих к нему слева - одептов плюсов, а справа - почетателей битоебского низкоуровневого язычка типа Си
                  Ответить
                  • А крестовый std::unique_ptr так не умеет?

                    Или там перепитушни много?
                    Ответить
    • Нет, указатель адрес - он не может работать для регистра, ибо у него нет адреса - это питушизм. Это работает только потому, что конпелятор это умеет. В реальном мире стек давно сдох.


      Алиас явно и чётко показывает идею - входящий елемент - есть алиас исходящего, как ссылка в путих С++. А с указателем ты такую фигню не сделаешь - только указатель на указатель.


      Аналогов биндов вообще нет, кроме того, что я наваял в первой портянке. Либо юзать структуры и питухуказатели, но это слишком тормазная питушня.


      Поэтому алиасы и указатели совершенно разные вещи, а бинды и кастыли со структурами - тоже разные вещи, ибо кастыли со структурами - питушня.
      Ответить
        • Я могу писать быстрее и лучше на сишке - мне удобней. Мне для этого не надо как рядовому питушку осиливать Сишку.

          Всё должно отражать всё - если твоей конпелятор написан как говно - он и оптимизировать будет как говно. И да, оптимизации не нужны я уже не помню где был тред, помоему на лоре.

          Вобще для моего мегаязыка оптимизации не нужны, ибо оптимизации нужны для питухов - там будет удобная ручная предсказуемость, как в ассемблере.

          В место питушских переменных - там буду переменные, который на самом деле по умолчанию безымянные регистры. Явный их биндинг на имена, явный ялиасинг. Никаких стеков и прочей ереси.

          Никаких автовекторизаций циклов( которые в 50% дают деградацию, допустим гцц(и все другие конпеляторы) по умолчанию вместо стекового фпу года гинерят ссе код, который медленее фпушного и теряют 10-30% производительности.

          Никаких разворачиваний циклов - нормальная автогинерациия кода в компилтайме, а не питушнян а шаблонах как в С++ и не ущербные макросы.

          Истинный компилтайм - для кода не будет существовать разницы между рантаймом и компилтаймом. Будет рантайм во время конпеляции - код будет сам гинерить то, что ему нужно.

          Ты пишешь char m[] = f(); в функции ты реализуешь заполнении массива, а конпелятор её исполняет. Нал оре был целый тред про constexp или как там его.

          Никаких оптимизаций циклов, никакой питушни - ты либо сам умеешь писать нормально циклы - либо иди в С++. Там за тебя в 20% случаев конпелятор заменит питушню на for(i) for(j) for(k) - на нормальный цикл на указателях, который работает в 3раза быстрее.

          И ещё масса всего - все эти оптимизации от бешенства с жиру - глянь на царский код, ему не нужны никакие оптимизации, кроме алиасинга( и то это из-за особенностей сишки).
          Ответить
          • > Любая ваша структура данных - это вариации на указателях

            Это справедливо только для классической питушни с адресным пространством, а есть еще всякие data-flow архитектуры, в которых адресуемой памяти вообще нихуя нет. В частности, для dataflow архитектур (которые очень часто реализуются поверх FPGA) применяются свои особые языки https://habrahabr.ru/post/122479/ вот статья со швабры например.
            Ответить
  • человек-программист
    человек-компилятор
    человек-отладчик
    человек-дизассемблер
    человек-интерпретатор
    Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8