Re[10]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 09:30
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> ПК>Вне зависимости от порядка вызовов функции, ее аргументы могут вычисляться в разной последовательности, а — теоретически — даже и одновременно.

>>
>> Почему же теортетически: на архитектурах с явным параллелизмом на уровне инструкций (например Itanium) так и есть.

ПК>Теоретически потому что я не видел компилятора, использующего эту возможность.


Любой компилятор под Itanium — так устроен процессор, что они исполняет срзу несколько команд, так что ни одному компилятору это обойти (если он хочет порождать хоть чуть-чуть эффективный код). Например MSVC или Intel. Ну да это не важно.

>> Собственно вопрос именно в этом и есть: где написано, что если есть хотя одна такая последовательность, то компилятор может выбрать именно ее.


ПК>Дело в обратном: нигде нет требования, чтобы он ее не выбирал.


Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.

ПК>В последних двух случаях между вычислением аргументов точек следования нет.


Какие могут быть варианты — понятно. Не понятно почему он может их свободно выбирать, если это нарушит работоспособность программы. Пример я уже приводил f(i++), f(i++) все должно вычисляться с лева-на-право (это не нарушено), но аргументы следую твоей логике получаем такую последовательность i++ i++ f() f(). Где фундаментальное отличие. То, что все реализаци понимают пример с запятой как надо — не доказательство.
Re[11]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 09:40
Оценка:
Здравствуйте, dupamid, Вы писали:

ПК>>Дело в обратном: нигде нет требования, чтобы он ее не выбирал.


D>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


Так об этом и речь. Не должен. Если в программе UB, компилятор не должен генерировать работающую программу.

D>Пример я уже приводил f(i++), f(i++)


Стоп-стоп-стоп! Здесь все определено. Откуда взялась запятая? До сих пор ее нигде не было.
Re[12]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 09:46
Оценка:
Здравствуйте, Аноним, Вы писали:

D>>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


А>Так об этом и речь. Не должен. Если в программе UB, компилятор не должен генерировать работающую программу.


Так следуя такой логике, что все что не запрещено разрешено — он ее вообще не обязан генерировать — даже если все определено

D>>Пример я уже приводил f(i++), f(i++)


А>Стоп-стоп-стоп! Здесь все определено. Откуда взялась запятая? До сих пор ее нигде не было.


Появилась Я обобщил логику выноса вычислений аргумента за перделы точки следования. Чтобы показать что если следовать такой логике, то не должны работать и более простые примеры.
Re[13]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 10:00
Оценка:
Здравствуйте, dupamid, Вы писали:

D>>>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


А>>Так об этом и речь. Не должен. Если в программе UB, компилятор не должен генерировать работающую программу.


D>Так следуя такой логике, что все что не запрещено разрешено — он ее вообще не обязан генерировать — даже если все определено


Гм, наверное, давайте не будем цепляться к слову "генерировать", и сформулируем следующим образом.

Поведение абстрактной машины, исполняющей программу, должно быть таким, какое описывает стандарт. Если стандарт не дает в каком-либо случае явного описания требуемого поведения (пресловутое UB), то поведение абстракной машины в этом случае может быть любым ("не должен генерировать работающую программу").

D>>>Пример я уже приводил f(i++), f(i++)


А>>Стоп-стоп-стоп! Здесь все определено. Откуда взялась запятая? До сих пор ее нигде не было.


D>Появилась Я обобщил логику выноса вычислений аргумента за перделы точки следования. Чтобы показать что если следовать такой логике, то не должны работать и более простые примеры.


Не вижу я в письме Павла никакого "выноса вычислений аргумента за перделы точки следования". В обсуждавшемся примере нет точки следования между двумя подвыражениями, содержащими модификацию переменной. Итого — UB. В Вашем новом примере такая точка следования появилась (как мы выяснили, ее вносит оператор запятая). Well-defined behavior.
Re[14]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 10:07
Оценка:
Здравствуйте, Аноним, Вы писали:

D>>>>Пример я уже приводил f(i++), f(i++)


А>>>Стоп-стоп-стоп! Здесь все определено. Откуда взялась запятая? До сих пор ее нигде не было.


D>>Появилась Я обобщил логику выноса вычислений аргумента за перделы точки следования. Чтобы показать что если следовать такой логике, то не должны работать и более простые примеры.


А>Не вижу я в письме Павла никакого "выноса вычислений аргумента за перделы точки следования". В обсуждавшемся примере нет точки следования между двумя подвыражениями, содержащими модификацию переменной. Итого — UB. В Вашем новом примере такая точка следования появилась (как мы выяснили, ее вносит оператор запятая). Well-defined behavior.


Точка следования есть в каждом из аргументов, так что не важно в какой последовательности они вычисляются. Так что для того чтобы вычислить значения аргументов обеих функций перед вызовам, нужно перенести код вычисления одного из операндов через точку следования другого операнда (какой будет первый, какой второй не важно — один из них будет, а код второго придется переносить через точку следования первого).
Re[11]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 10:13
Оценка:
>>> Собственно вопрос именно в этом и есть: где написано, что если есть хотя одна такая последовательность, то компилятор может выбрать именно ее.
>
> ПК>Дело в обратном: нигде нет требования, чтобы он ее не выбирал.
>
> Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму

В случае наличия undefined behavior — конечно. В противном случае (1.4/2):

If a program contains no violations of the rules in this International Standard, a conforming implementation shall, within its resource limits, accept and correctly execute3) that program.


> ПК>В последних двух случаях между вычислением аргументов точек следования нет.

>
> Какие могут быть варианты — понятно. Не понятно почему он может их свободно выбирать, если это нарушит работоспособность программы.

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

> Пример я уже приводил f(i++), f(i++) все должно вычисляться с лева-на-право (это не нарушено), но аргументы следую твоей логике получаем такую последовательность i++ i++ f() f(). Где фундаментальное отличие.


Фундаментальное отличие в том, что в случае наличия запятой, стандарт явно определяет порядок вычислений:

All side effects (1.9) of the left expression, except for the destruction of temporaries (12.2), are performed before the evaluation of the right expression.

В примере без запятой какого-либо определенного порядка нет.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 10:28
Оценка: 14 (2)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Теоретически потому что я не видел компилятора, использующего эту возможность.


Может быть кому-нибудь будет интересно посмотреть на код для процессора с явным пераллелизмом на уровне инструкцийй:
int i, j;

int main()
{
    return ++i + ++j;
}

Выдержка из получающегося ассемблерника для Itanium с моими комментариями

main:
{.mii
    add    r11=@gprel(j#),gp // загрузим смещения переменных i и j
    add    r10=@gprel(i#),gp
    nop.i   0 ;; // так обозначается та самая пресловутаю "точка следования" в asm :)
}
{.mmi
    ld4    r9=[r11]   // загрузим значения переменных
    ld4    r8=[r10]
    nop.i   0 ;;       // "точка следования"
}
{.mii
    add    r3=1,r9    // к каждому прибавим по 1 
    add    r2=1,r8 ;; // "точка следования", ждем завершения предыдущих операций
    add    r8=r2,r3   // складываем
}
{.mmi
    st4    [r11]=r3   // сохраняем новые значения переменных
    st4    [r10]=r2
    nop.i   0 ;;
}
{.mib
    nop.m   0                
    nop.i   0                
    br.ret.sptk.many b0 ;; // возвращаемся, в r8 - результат
}
Re[15]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 10:34
Оценка:
> Точка следования есть в каждом из аргументов, так что не важно в какой последовательности они вычисляются. Так что для того чтобы вычислить значения аргументов обеих функций перед вызовам, нужно перенести код вычисления одного из операндов через точку следования другого операнда (какой будет первый, какой второй не важно — один из них будет, а код второго придется переносить через точку следования первого).

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

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.

Единственное, что стандарт определяет в этом отношении — относительный порядок вычисления аргументов функции и ее вызова. Т.е. аргументы будут вычислены до вызова функции, в которую они передаются. Будет это сделано до вызова других функций в том же выражении, или после — стандарт не определяет.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[12]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 10:46
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> Пример я уже приводил f(i++), f(i++) все должно вычисляться с лева-на-право (это не нарушено), но аргументы следую твоей логике получаем такую последовательность i++ i++ f() f(). Где фундаментальное отличие.


ПК>Фундаментальное отличие в том, что в случае наличия запятой, стандарт явно определяет порядок вычислений:

ПК>

All side effects (1.9) of the left expression, except for the destruction of temporaries (12.2), are performed before the evaluation of the right expression.

ПК>В примере без запятой какого-либо определенного порядка нет.

А порядок и не нарушается, в начале вычисляется левый операнд (только в него подмешивается правый операнд ) все его побочные действия завершаются, потом довычисляется правый, и все его побочные действия завершаются. Так что порядок не нарушился в соответствии с этим пунктом. Мы просто начали вычислять второй операнд до точки следования.
Re[7]: sequence point (по мотивам инкремента)
От: jazzer Россия Skype: enerjazzer
Дата: 04.06.04 11:26
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> ПК>И второе тоже: побочные эффекты выражения не могут начаться раньше его вычисления :-)

>>
>> А есть ли в Стандарте такое требование? ;)

ПК>Это уже машина времени какая-то получается :)


необязательно
это может быть второй процессор :)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: sequence point (по мотивам инкремента)
От: Lorenzo_LAMAS  
Дата: 04.06.04 12:15
Оценка:
Здесь есть UB.
Of course, the code must be complete enough to compile and link.
Re[6]: sequence point (по мотивам инкремента)
От: Lorenzo_LAMAS  
Дата: 04.06.04 12:25
Оценка:
А>(Должен сказать, что в этом вопросе я несколько радикальнее Павла. По моему мнению, например, в следующем примере — UB:
А>
А>    i = (++i, 0);
А>

А>Павел, если я все правильно помню, с этим согласен не был.)

А не могли бы Вы объяснить в чем тут, по Вашему мнению, дело? Т.е. Вы считаете, что все-таки между двумя точками следования i модифицируется дважды благодаря ++ и присваиванию и несмотря на точку следования после ',' ?
Of course, the code must be complete enough to compile and link.
Re[7]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 13:38
Оценка: 5 (1)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

А>>(Должен сказать, что в этом вопросе я несколько радикальнее Павла. По моему мнению, например, в следующем примере — UB:

А>>
А>>    i = (++i, 0);
А>>

А>>Павел, если я все правильно помню, с этим согласен не был.)

L_L>А не могли бы Вы объяснить в чем тут, по Вашему мнению, дело? Т.е. Вы считаете, что все-таки между двумя точками следования i модифицируется дважды благодаря ++ и присваиванию и несмотря на точку следования после ',' ?


Да. Пронумеруем для наглядности точки следования.
    i = (++i, 0)  ;
  ^         ^    ^
  1         2    3
1 — где-то перед полным выражением; 2 — ее образует оператор запятая; 3 — в конце полного выражения.
У нас есть так же два побочных эффекта: присваивание и инкремент. Мы можем утверждать, что побочный эффект инкремента должен произойти между точками следования 1 и 2. Но о побочном эффекте присваивания мы можем сказать лишь, что он должен произойти между точками следования 1 и 3. Ни из чего в стандарте не следует, что побочный эффект присваивания должен происходить после всех побочных эффектов подвыражения в правой части.

Иначе. Этот пример можно рассматривать следующим образом.
    i = A;
где подвыражение A модифицирует переменную i. Точек следования в полном выражении нет. Переменная i модифицируется более одного раза между двумя соседними точками следования (1 и 3).

P.S. В этом документе дается более подробное и лучше формализованное, чем в стандартах C/C++, описание точек следования. (В нем, в частности, рассматриваемый пример имеет well-defined behavior.) Но документ этот так и не стал нормативным ни для C, ни для C++.
Re[8]: sequence point (по мотивам инкремента)
От: jazzer Россия Skype: enerjazzer
Дата: 04.06.04 14:36
Оценка:
Здравствуйте, Аноним, Вы писали:

Вы бы зарегистировались, что ли...
А то все Аноним до Аноним...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: sequence point (по мотивам инкремента)
От: elcste  
Дата: 04.06.04 15:16
Оценка: 15 (1) :))) :)
Здравствуйте, jazzer, Вы писали:

J>Вы бы зарегистировались, что ли...

J>А то все Аноним до Аноним...

Ну что вы все пристали с этой регистрацией...
Re[8]: sequence point (по мотивам инкремента)
От: Ivan A. Kosarev  
Дата: 04.06.04 17:17
Оценка:
wrote in message news:667226@news.rsdn.ru...

> P.S. В этом документе дается более подробное и лучше формализованное, чем в стандартах C/C++, описание точек следования. (В нем, в частности, рассматриваемый пример имеет well-defined behavior.) Но документ этот так и не стал нормативным ни для C, ни для C++.


Это более подробное и формализированное изложение того, что не может быть принято. Существуют практически важные примеры, не укладывающиеся в такое определение точек следования.

>
>     i = A;
>
где подвыражение A модифицирует переменную i. Точек следования в полном выражении нет. Переменная i модифицируется более одного раза между двумя соседними точками следования (1 и 3).


Есть хороший пример на эту тему:

i = f(&i);

Здесь точка следования есть, но сути это не меняет.

Еще вспоминаю давнюю дискуссию между Павлом Кузнецовым и dupamid. Павел говорил о неатомарности присваиваний. Так вот кроме того, что об атомарности (кроме sig_atomic_t и смежного с ним) в стандартах ничего не говорится, существует значительная масса кода в духе

link = link -> next;

которая никакой неатомарности не потерпит.

--
Иван

9899 — Полный справочник по языку Си
http://subscribe.ru/catalog/comp.soft.prog.9899
Posted via RSDN NNTP Server 1.9 alpha
Re[11]: sequence point (по мотивам инкремента)
От: Шахтер Интернет  
Дата: 05.06.04 00:20
Оценка:
Здравствуйте, dupamid, Вы писали:

D>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


Вот конкретный пример. Можете его откомпилировать под Itanium.

int fun(int *i,int *j) { return ++(*i) + ++(*j); }


Данная функция нормально себя ведет, если i и j указывают на разные переменные и в этом случае параллелизация инкрементов -- хорошая идея.
Но вот если они указывают на одну переменную...

P.S. Пример несколько исскуственный.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[12]: sequence point (по мотивам инкремента)
От: folk Россия  
Дата: 05.06.04 02:19
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Здравствуйте, dupamid, Вы писали:


D>>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


Ш>Вот конкретный пример. Можете его откомпилировать под Itanium.


Ш>
Ш>int fun(int *i,int *j) { return ++(*i) + ++(*j); }
Ш>


Ш>Данная функция нормально себя ведет, если i и j указывают на разные переменные и в этом случае параллелизация инкрементов -- хорошая идея.

Ш>Но вот если они указывают на одну переменную...

Ну так здесь неопределенное поведение в случае, когда i и j указывают на одну переменную. После асма dupamida такое ограничение мне начинает казаться разумным.

Кстати, в студенчестве мы проходили среди прочего конвейерные (команда может быть выбрана на исполнение до завершения исполнения предыдущей команды) и суперскалярные (несколько одновременно работающих конвейеров) архитектуры процессоров. Помню что некоторые процессоры с помощью какой-то магии умеют определять истинные зависимости по данным такого рода (чтение после записи) и в качестве контрмеры приостанавливают конвейер(ы), пока не будет завершено выполнение первой команды. Может Itanium тоже так умеет и в ситуации, когда i и j указывают на один объект, инкременты будут выполнены последовательно?

Ш>P.S. Пример несколько исскуственный.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[13]: sequence point (по мотивам инкремента)
От: Шахтер Интернет  
Дата: 05.06.04 03:23
Оценка:
Здравствуйте, folk, Вы писали:

F>Здравствуйте, Шахтер, Вы писали:


Ш>>Здравствуйте, dupamid, Вы писали:


D>>>Это странное утверждение. Обощая можно получить, что компилятор вообще не должен генерировать работающую прогроамму Хотелось бы чего-то более конкретного.


Ш>>Вот конкретный пример. Можете его откомпилировать под Itanium.


Ш>>
Ш>>int fun(int *i,int *j) { return ++(*i) + ++(*j); }
Ш>>


Ш>>Данная функция нормально себя ведет, если i и j указывают на разные переменные и в этом случае параллелизация инкрементов -- хорошая идея.

Ш>>Но вот если они указывают на одну переменную...

F>Ну так здесь неопределенное поведение в случае, когда i и j указывают на одну переменную.


Ага. Вопрос только -- зачем компилятору генерировать "плохой" код.

F>После асма dupamida такое ограничение мне начинает казаться разумным.


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


F>Помню что некоторые процессоры с помощью какой-то магии умеют определять истинные зависимости по данным такого рода (чтение после записи) и в качестве контрмеры приостанавливают конвейер(ы), пока не будет завершено выполнение первой команды.


Не некоторые. Все современные процессоры -- конвейерные. И все они осуществляют приостановку конвейера при возникновении зависимости между входом и выходом.
Иначе такой процессор невозможно было бы использовать. Магии тут нет никакой -- просто схемотехника.

Если интересно и есть свободное время, можешь глянуть вот этот документ.
Особенно главу Pipeline.

F>Может Itanium тоже так умеет и в ситуации, когда i и j указывают на один объект, инкременты будут выполнены последовательно?


Зависит от того, что сгенерирует компилятор.

Пример (условный). В одной строчке -- параллельно выполняющиеся команды.

i = [SP+offset i]
j = [SP+offset j]

R1 <- i R2 <- j
R3 <- [R1] R4 <- [R2]
R3++ R4++
R0 <- R3 + R4 // возвращаем значение в R0
i <- R3 j <- R4

В последнеё строчке конфликт доступа к памяти. Проц как-то разрешит его, но это не сделает результат работы функции осмысленным.

Пусть i и j указывают на одну ячейку со значением 0. Тогда функция вернет 2. При последоватнльном же выполнении, т.е.

int i_res=++(*i); 
int j_res=++(*j);

return i_res+j_res; // Всё что мы сделали -- разбили выражение на два подвыражения.


функция вернула бы 3.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[13]: sequence point (по мотивам инкремента)
От: folk Россия  
Дата: 05.06.04 03:24
Оценка:
Здравствуйте, folk, Вы писали:

[]

F>Кстати, в студенчестве мы проходили среди прочего конвейерные (команда может быть выбрана на исполнение до завершения исполнения предыдущей команды) и суперскалярные (несколько одновременно работающих конвейеров) архитектуры процессоров. Помню что некоторые процессоры с помощью какой-то магии умеют определять истинные зависимости по данным такого рода (чтение после записи) и в качестве контрмеры приостанавливают конвейер(ы), пока не будет завершено выполнение первой команды. Может Itanium тоже так умеет и в ситуации, когда i и j указывают на один объект, инкременты будут выполнены последовательно?


Скорее всего я выдавал желаемое за действительное. Скорее всего могут отслеживаться зависимости по данным для регистров процессора, что особенно актуально при неупорядоченном выполнении команд. А в нашем случае связь между *i и *j разрывается в момент их загрузки в разные регистры. Чтобы разруливать подобные ситуации нужна очень сильная магия
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.