Тип RHS операнд при побитово изместване на типове без знак

Искам да преместя неподписан тип (напр. size_t) с неотрицателен брой (двоични) цифри / места наляво/надясно, напр.

size_t x;
x << non_const_expr

при предположенията, че стойността на non_const_expr се вписва в (unsigned) int и never причинява недефинирано поведение (стойността му е неотрицателна и не надвишава броя на цифрите в x). (Имайте предвид, че стойността е неизвестна по време на компилиране.)

Да предположим, че такава промяна се случва в критична за производителността секция (напр. това е единствената операция в най-вътрешния цикъл). Моята трилема е кой тип правилният операнд (връщащият тип на non_consts_expr) в идеалния случай трябва да бъде за най-бързата операция за преместване:

  • unsigned int изглежда най-четлив/интуитивен)
  • int (AFAIK int е естественият (и най-бързият?) тип на платформата, докато unsigned може да се внедри по по-малко ефективен начин`)
  • типът на LHS в операцията на смяна (т.е. size_t в този случай)

Има ли изобщо значение? Ако да, кой като цяло води до най-бърз код?


person eold    schedule 01.04.2014    source източник
comment
Винаги можете да използвате std::uint_fast32_t, ако се притеснявате за производителността на unsigned int типове и това трябва да ви даде бърз.   -  person Jay    schedule 01.04.2014
comment
Не мисля, че има значение. Имате ли доказателства, че тази инструкция за смяна е тясно място в работата?   -  person Filipe Gonçalves    schedule 01.04.2014
comment
Уверен, че тъй като смяната е дефинирана само за да речем 0 до 31 (предвид 32-битов x) и всичко останало е UB, повечето (невестулки думи) просто ще използват 5-те LSbits на non_const_expr независимо от неговия тип .   -  person chux - Reinstate Monica    schedule 01.04.2014
comment
Целочисленият LHS тип, който съответства на основния размер на процесора, със сигурност не е по-бавен от всичко друго. т.е. Най-бързият, въпреки че други видове може да са също толкова бързи.   -  person chux - Reinstate Monica    schedule 01.04.2014
comment
Забележка: Много процесори, по дизайн, не се изместват според броя, а по-скоро чрез X LSBits от броя. BITD, 8088 ще измести 16-битов int въз основа на 8-те LSBita на броя. Всяка смяна отне 1 цикъл. Така че, ако броят е бил глупаво 255, тази инструкция отнема много време. По този начин се създава огромно време за забавяне в по-лош случай за прекъсвания. Intel разумно използва 4 (или 5) LSBita за следващите процесори.   -  person chux - Reinstate Monica    schedule 01.04.2014
comment
Основните ми опасения са, че ако избера неподходящ тип, компилаторът може да генерира допълнителни проверки/инструкции, които не биха били генерирани иначе. Например компилаторът може да е твърде умен и да направи добре дефинирани отрицателни смени чрез вмъкване на допълнителен код за асемблиране, така че правенето на RHS без знак би елиминирало този опит може би.   -  person eold    schedule 01.04.2014
comment
(подписано) int позволява отрицателни суми на преместване, което е недефинирано поведение на повечето платформи.   -  person Thomas Matthews    schedule 01.04.2014
comment
@OP, non_const_expr еднаква ли е стойността вътре в критичната за производителността секция? Ако е така, обадете се на код, който използва фиксирана смяна. if (non_const_expr==5) for(i=n; i>0; i--) { foo1(); x << 5; foo2(); }. Някак си, в края на деня, просто не виждам оптимизирането на тази смяна ще направи значителна разлика в скоростта.   -  person chux - Reinstate Monica    schedule 01.04.2014


Отговори (1)


Оптималното представяне на ляво или дясно преместване е, когато RHS е положителна числена константа.

Иначе зависи от процесора.

Предлагам ви да кодирате различни примери и да разгледате кода на асемблерния език, генериран от компилатора. Можете също така да коригирате настройките за оптимизация, за да видите дали имат някакво влияние.

В процесора ARM7 може да възникне операция за смяна с инструкция за зареждане на регистър; в противен случай ще зареди стойност, след което ще използва инструкция за сглобяване на смяна.

Ако използвате променлива за RHS, вие разглеждате минималните операции:

  1. Заредете RHS от паметта.
  2. Преместете регистъра, съдържащ LHS стойността, с RHS стойността.
  3. Запазете резултата в паметта.

Истината ще бъде в списъка на асемблерния език.

Оптимизациите на това ниво често не водят до незначителни печалби в производителността. Обикновено по-големи печалби могат да бъдат намерени чрез оптимизиране на дизайна или кода другаде.

person Thomas Matthews    schedule 01.04.2014