Зачем передавать string_view по значению?И почему Visual Studio не может оптимизировать это? - PullRequest
0 голосов
/ 04 июня 2018

Используя мои интуитивные ощущения, я предполагал, что новый string_view необходимо передать по ссылке, поскольку это более эффективно (только указатель передачи вместо полного класса).Однако некоторые источники указывают, что лучше передавать его по значению, избегая проблемы с псевдонимами.

Испытывая несколько альтернатив, я подтвердил свое интуитивное чувство, что передача по ссылке была быстрее, если функция не делала ничего, кроме пересылки string_view (все источники, скомпилированные с /Ox)

Например, этот код

extern auto otherMethodByReference(const std::string_view &input) -> void;
auto thisMethodByReference(int value, const std::string_view &input) -> void
   {
   otherMethodByReference(input);
   }

Приведен в этой сборке

00000   48 8b ca     mov     rcx, rdx
00003   e9 00 00 00 00   jmp     ?otherMethodByReference@@YAXAEBV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z ; otherMethodByReference

При этом код

extern auto otherMethodByValue(std::string_view input) -> void;
auto thisMethodByValue(int value, std::string_view input) -> void
   {
   otherMethodByValue(input);
   }

Приведен вэта сборка

00000   48 83 ec 38  sub     rsp, 56            ; 00000038H
00004   0f 10 02     movups  xmm0, XMMWORD PTR [rdx]
00007   48 8d 4c 24 20   lea     rcx, QWORD PTR $T1[rsp]
0000c   0f 29 44 24 20   movaps  XMMWORD PTR $T1[rsp], xmm0
00011   e8 00 00 00 00   call    ?otherMethodByValue@@YAXV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z ; otherMethodByValue
00016   48 83 c4 38  add     rsp, 56            ; 00000038H
0001a   c3       ret     0

Ясно, что вы можете видеть, что копия string_view создается в стеке и затем передается другому методу.

Однако мне было интересно, почему некомпилятор оптимизирует это и просто передает аргумент string_view непосредственно другому методу.В конце концов, в Windows x64 ABI передача значения класса больше, чем умещается в регистре, всегда выполняется путем копирования регистра в стек и передачи указателя на него в правильном регистре.В этом примере кода я ожидаю, что компилятор просто перенаправит указатель на следующую функцию, как в случае передачи по ссылке.В конце концов, компилятор может видеть, что значение аргумента впоследствии не используется, поэтому вместо создания копии он может просто переслать адрес.

Я попытался добавить к вызову std :: move, напримерthis:

auto thisMethodByValueAndMove(int value, std::string_view input) -> void
   {
   otherMethodByValue(std::move(input));
   }

Но это, похоже, не помогает.

Есть ли причина, по которой компилятор Visual Studio 2017 не может оптимизировать это?Оптимизируют ли другие компиляторы этот шаблон?

1 Ответ

0 голосов
/ 09 июля 2019

Соглашение о вызовах X64 не позволяет распределять аргументы по разным регистрам.Компилятор может передавать string_view через rcx и rdx, но ABI против этого.https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019

...