Шахтер:
> ПК>Не обязательно разыменование. Можно и копирование... В присутствии оптимизации — вполне может. Всё зависит от сложности кода и логики оптимизатора...
> Вообще-то, оптимизатор должен оптимизировать код.
При этом оптимизация может быть как по размеру, так и по скорости. И для обоих случаев можно вполне представить примеры, когда ранняя загрузка сегментного регистра может быть выгоднее, чем поздняя.
> Может вы подскажите, что это за чудо процессор такой, у которого загрузка сегментного регистра с проверкой селектора сегмента выполняется быстрее, чем простая загрузка регистра общего назначения?
Давай представим, что загрузка сегментного регистра в 10000 раз медленее, чем загрузка регистра общего назначения — так даже нагляднее получится. И представим такой гипотетический пример:
int f(A* a, B* b, int size)
{
int result = 0;
for (int i = 0; i < size; ++i)
{
if (a->f(i))
result += a->g(i, b);
else
result += b->h(i);
}
}
Можно легко заметить, что непосредственно в данной функции b разыменовывается только в одной из веток. Но если в результате какой-нибудь profile-guided оптимизации выяснится, что вынесение загрузки b в сегментный регистр за пределы цикла уменьшает среднее время исполнения этой функции в 10 раз, то я вполне пойму логику оптимизатора, загружающего сегментный регистр заранее, даже если иногда при вызове этой функции ветка с разыменованием b вообще не будет выполняться.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Шахтер:
>> ПК>Не обязательно разыменование. Можно и копирование... В присутствии оптимизации — вполне может. Всё зависит от сложности кода и логики оптимизатора...
>> Вообще-то, оптимизатор должен оптимизировать код.
ПК>При этом оптимизация может быть как по размеру, так и по скорости. И для обоих случаев можно вполне представить примеры, когда ранняя загрузка сегментного регистра может быть выгоднее, чем поздняя.
>> Может вы подскажите, что это за чудо процессор такой, у которого загрузка сегментного регистра с проверкой селектора сегмента выполняется быстрее, чем простая загрузка регистра общего назначения?
ПК>Давай представим, что загрузка сегментного регистра в 10000 раз медленее, чем загрузка регистра общего назначения — так даже нагляднее получится. И представим такой гипотетический пример: ПК>
ПК>int f(A* a, B* b, int size)
ПК>{
ПК> int result = 0;
ПК> for (int i = 0; i < size; ++i)
ПК> {
ПК> if (a->f(i))
ПК> result += a->g(i, b);
ПК> else
ПК> result += b->h(i);
ПК> }
ПК>}
ПК>
ПК>Можно легко заметить, что непосредственно в данной функции b разыменовывается только в одной из веток. Но если в результате какой-нибудь profile-guided оптимизации выяснится, что вынесение загрузки b в сегментный регистр за пределы цикла уменьшает среднее время исполнения этой функции в 10 раз, то я вполне пойму логику оптимизатора, загружающего сегментный регистр заранее, даже если иногда при вызове этой функции ветка с разыменованием b вообще не будет выполняться.
Боюсь, что пример не корректен. Если я передам в b нулевой укащатель(а это вполне законно), то при ранней загрузке сегментного регистра получу исключение. Так что данная оптимизация некорректна.
А вообще, с тяжелыми сегментными регистрами так не работают. Их обычно загружают вручную и не меняют без нужды.
Вообщем, я пока не вижу большой пользы от запрета копирования неинициализированных фундаментальных типов, включая указатели. Тем более, что наиболее распространённые платформы это допускают.
Шахтер:
> Боюсь, что пример не корректен. Если я передам в b нулевой укащатель(а это вполне законно), то при ранней загрузке сегментного регистра получу исключение. Так что данная оптимизация некорректна.
Оптимизатор вполне может включить проверку на 0
> Вообщем, я пока не вижу большой пользы от запрета копирования неинициализированных фундаментальных типов, включая указатели. Тем более, что наиболее распространённые платформы это допускают.
Для платформ, на которых это допустимо, неопределенное поведение всегда можно определить. А вот что делать с теми платформами, у которых подобные операции недопустимы?
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Шахтер:
>> Боюсь, что пример не корректен. Если я передам в b нулевой укащатель(а это вполне законно), то при ранней загрузке сегментного регистра получу исключение. Так что данная оптимизация некорректна.
ПК>Оптимизатор вполне может включить проверку на 0
Т.е. фактически, данный вид оптимизации будет базироваться на запрете копирования неинициализированных указателей. А теперь вынесем этот код из функции в блок
{
...
{
A* a=что-то, B* b, int size=что-то;
int result = 0;
for (int i = 0; i < size; ++i)
{
if (a->f(i))
result += a->g(i, b);
else
result += b->h(i);
}
}
...
}
Этот фрагмент не содержит UB, если else не выполняется. Т.е. его оптимизировать таким способом уже нельзя. Хождение по краю какое-то.
>> Вообщем, я пока не вижу большой пользы от запрета копирования неинициализированных фундаментальных типов, включая указатели. Тем более, что наиболее распространённые платформы это допускают.
ПК>Для платформ, на которых это допустимо, неопределенное поведение всегда можно определить. А вот что делать с теми платформами, у которых подобные операции недопустимы?
А между прочим, есть выход. Уровни конформантности. Т.е. компилятор должен явно декларировать некоторые свойства платформы. Скажем, путем определения макросимволов. В тот же __cplusplus можно зафигачить набор флагов. И выбирать код, соответствующий платформе.
Шахтер:
> Т.е. фактически, данный вид оптимизации будет базироваться на запрете копирования неинициализированных указателей. А теперь вынесем этот код из функции в блок >
> {
> ...
> {
> A* a=что-то, B* b, int size=что-то;
>
> int result = 0;
> for (int i = 0; i < size; ++i)
> {
> if (a->f(i))
> result += a->g(i, b);
> else
> result += b->h(i);
> }
> }
> ...
> }
>
> Этот фрагмент не содержит UB, если else не выполняется
Почему не содержит? Копирование невалидного указателя все равно происходит...
> ПК>Для платформ, на которых это допустимо, неопределенное поведение всегда можно определить. А вот что делать с теми платформами, у которых подобные операции недопустимы?
> А между прочим, есть выход. Уровни конформантности. Т.е. компилятор должен явно декларировать некоторые свойства платформы. Скажем, путем определения макросимволов. В тот же __cplusplus можно зафигачить набор флагов. И выбирать код, соответствующий платформе.
На практике это приведет к провоцированию появления множества диалектов языка, что вряд ли можно назвать хорошим делом.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Шахтер:
>> Т.е. фактически, данный вид оптимизации будет базироваться на запрете копирования неинициализированных указателей. А теперь вынесем этот код из функции в блок >>
>> {
>> ...
>> {
>> A* a=что-то, B* b, int size=что-то;
>>
>> int result = 0;
>> for (int i = 0; i < size; ++i)
>> {
>> if (a->f(i))
>> result += a->g(i, b);
>> else
>> result += b->h(i);
>> }
>> }
>> ...
>> }
>>
>> Этот фрагмент не содержит UB, если else не выполняется
ПК>Почему не содержит? Копирование невалидного указателя все равно происходит...
Вот так тогда.
{
...
{
A* a=что-то, B* b, int size=что-то;
int result = 0;
for (int i = 0; i < size; ++i)
{
if (a->f(i))
result += a->g(i);
else
result += b->h(i);
}
}
...
}
Кстати, я что-то протормозил с проверкой на нуль. Это сделать конечно можно, но придётся код цикла сдубрировать, поскольку он будет завязан на предположение о предзагрузке, а в случае нулевого указателя это предположение неверно.
>> ПК>Для платформ, на которых это допустимо, неопределенное поведение всегда можно определить. А вот что делать с теми платформами, у которых подобные операции недопустимы?
>> А между прочим, есть выход. Уровни конформантности. Т.е. компилятор должен явно декларировать некоторые свойства платформы. Скажем, путем определения макросимволов. В тот же __cplusplus можно зафигачить набор флагов. И выбирать код, соответствующий платформе.
ПК>На практике это приведет к провоцированию появления множества диалектов языка, что вряд ли можно назвать хорошим делом.
ЭЭЭ. Да эти диалекты уже существуют по факту. Поздно пить боржоми. Совсем поздно. Даже гемодиализ не спасет.
Как раз наоборот, было бы полезно этот дикий сейчас процесс ввести в нормальное русло -- т.е. оформить де юре, то что уже и так существует де факто. Это даст возможность упростить перенос кода между платформами, потому что специфические куски кода будут явно выделены.
Имо, в данном случае это экономия на спичках, от которой мало пользы. И вообще, когда несколько месяцев назад смотрел yasli::vector, сложилось впечатление, что ясландеры иногда уделяют слишком много внимания всякой мелочной фигне, вместо того чтобы потратить время на что-нибудь более полезное.
Например запомнилась специализация функции destroy для примитивных типов, которая ничего не делает. Вменяемый оптимизатор и сам сможет выкинуть цикл for( ; p != end; ++p ) p->~T(); если T имеет тривиальный деструктор. А значит нефиг усложнять код ненужными подробностями.
мы имеем одну операцию чтения из памяти и две записи.
В этом варианте
ebo_.beg_ = 0;
end_ = 0;
eos_ = 0;
три операции записи. Скорее всего, тоже на тоже и выйдет. А, кроме того, если посмотреть другие методы, например empty() или деструктор, то там теперь приходится делать две операции чтения из памяти вместо одной, т.е. идёт проигрышь. Суммарный эффект, скорее всего, будет отрицательный.
F>И вообще, когда несколько месяцев назад смотрел yasli::vector, сложилось впечатление, что ясландеры иногда уделяют слишком много внимания всякой мелочной фигне, вместо того чтобы потратить время на что-нибудь более полезное.
Да, есть такое ощущение. Похоже, у Александреску остроумия больше, чем здравого смысла.
F>Например запомнилась специализация функции destroy для примитивных типов, которая ничего не делает. Вменяемый оптимизатор и сам сможет выкинуть цикл for( ; p != end; ++p ) p->~T(); если T имеет тривиальный деструктор. А значит нефиг усложнять код ненужными подробностями.