LINUX.ORG.RU

Как заставить компилятор сгенерировать нормальный код

 ,


1

5

Нужен нормальный способ сказать компилятору что 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 - три раза за итерацию лезет в память. Разумеется, подобный код сливает в тестах производительности. Есть решение лучше, чем локальные переменные заводить каждый раз?

Отвечу не в тему.

Твой пример - это не код на с++, это си-код.

std::fill(b, e, v);
anonymous ()
Ответ на: комментарий от rupert

Добавь в конце b = e; для «эквивалентности» функций.

И оптимизация «-Os».

anonymous ()

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

Выносишь этот участок кода в функцию и объявляешь аргументы с __restrict

annulen ★★★★★ ()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

Тут скорее всего проблема в том, что используются внешние по отношению к функции переменные. Эти значения надо как-то взять под «контроль», например, скопировать в локальные переменные, или передать как параметры функции.

anonymous ()
Ответ на: комментарий от annulen

Да, прокатит, конечно. Но остальные случаи нужно будет вручную найти. Может тулза какая есть? Профилировщик такое ловит очень неохотно

DllMain ()
Ответ на: комментарий от DllMain

Профилировщик такое ловит очень неохотно

Значит и необходимости это делать нет. А вот возможность накосячить и переоптимизировать случай, где алиасинг возможен, есть.

annulen ★★★★★ ()
Последнее исправление: annulen (всего исправлений: 1)

Для GCC неплохо работает такой костыль, причем примерно для всех архитектур (не только x86).

CLANG его тоже компилирует, но начиная с 5.x парсит семантику, видит запись в char* и всё равно «включает» алиасинг.

А вообще тема отсутствия restrict_char_ptr больная, и логику C++-комитета в отношении явного restrict я не понимаю.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от SZT

Вместо char можно использовать структуру с char внутри.

Не поможет, это было-бы слишком просто )

Чуть менее чем все компиляторы действуют по правилу: если есть разыменование указателя на какой-нибудь одно-байтовый тип и это не bool, то возможен алиасинг. Причем __restrict работает (не игнорируется) только для аргументов функций и если среди аргументов более одного указателя.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от SZT

Это первое, что я попробовал. Но standard layout type -> first member - тоже корректный алиасинг(не говоря о том, что gcc с int, long и пр. осторожничает)

DllMain ()
Ответ на: комментарий от Deleted

Да уж, надо GCC-шникам сказать чтоб придумали антипод для __attribute__((__may_alias__))

SZT ★★★★★ ()

Включить С++20 опцией -std=c++2a и использовать char8_t вместо char.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.