Что такое нижняя и верхняя части умножения в инструкциях по сборке - PullRequest
0 голосов
/ 23 октября 2018

Я читал эту ссылку , короче говоря, кто-то может объяснить проблему с текущим компилятором C ++ кому-то, кто начал изучать сборку x86 и 64-битной версии неделю назад.

К сожалению,Текущие компиляторы не оптимизируют красивую переносимую версию @ craigster0, поэтому, если вы хотите использовать преимущества 64-битных процессоров, вы не можете использовать ее, кроме как в качестве запасного варианта для целей, для которых у вас нет #ifdef.(Я не вижу общего способа его оптимизации; вам нужен 128-битный тип или встроенный.)

для пояснения. Я искал преимущества сборки, когда натолкнулся на людей, говорящихво многих постах текущие компиляторы не оптимизируются, когда речь идет о умножении на 64-битные, потому что они используют младшую часть, поэтому они не выполняют полное 64-битное умножение, что это значит.так в чем же смысл получения верхней части, и я прочитал в моей книге, что в 64-битной архитектуре для RF-флагов используются только самые младшие 32-битные. Связаны ли они, я запутался?

1 Ответ

0 голосов
/ 23 октября 2018

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

Например, на x86, если вы умножаете два 32-битные числа, вы получите верхние 32 бита результата в EDX и младшие 32 бита результата в EAX.Если вы умножите два 64-битных числа, вы получите результаты в RDX и RAX.

На других процессорах используются другие регистры, но применяется та же основная идея: один регистр, умноженный на один регистр, дает результат, которыйзаполняет два регистра.

C и C ++ не предоставляют простой способ воспользоваться этой возможностью.Когда вы работаете с типами, меньшими int, входные операнды преобразуются в int, затем умножаются числа, и в результате получается int.Если входные данные больше, чем int, то они умножаются на один и тот же тип, а результат - того же типа.Ничего не делается для того, чтобы принять во внимание, что результат в два раза больше, чем типы входов, и практически каждый процессор на земле будет давать результат, вдвое больший, чем каждый вход индивидуально.

Есть, конечно,способы борьбы с этим.Самым простым является базовый фактор, который мы выучили в начальной школе: возьмите каждое число и разбейте его на верхнюю и нижнюю половинки.Затем мы можем умножить эти части по отдельности: (a + b) * (c + d) = ac + ad + bc + bd.Поскольку каждое из этих умножений имеет только половину ненулевых битов, мы можем выполнить каждый фрагмент арифметики как половинную операцию, получая полноразмерный результат (плюс один бит, полученный из сложения).Например, если мы хотим выполнить 64-битное умножение на 64-битном процессоре, чтобы получить 128-битный результат, мы разбили бы каждый 64-битный ввод на 32-битные части.Тогда каждое умножение даст 64-битный результат.Затем мы сложили бы куски вместе (с подходящими сдвигами битов), чтобы получить наш окончательный 128-битный результат.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...