Сообщение Re[3]: Почему нет принудительного TCO? от 11.02.2022 9:54
Изменено 11.02.2022 11:36 netch80
Re[3]: Почему нет принудительного TCO?
Здравствуйте, cppguard, Вы писали:
C>Вот за это люблю С++: на одном ресурсе обсуждаешь что-то из стандарта, и тебе говорят про необязательное существование стека (я бы очень хотел взглянуть на эти платформы),
Тут может быть два разных случая:
1. Стека формально нет в архитектуре, но нет проблем его сэмулировать для языка типа C/C++.
Это, например, обыкновеннейшая System/Z, потомок IBM 360.
Стек для C и других подобных эмулируется через регистр 15.
2. Стека нет в архитектуре и ресурсы не позволяют сэмулировать его. Это вообще исключает рекурсию.
Из опыта — такое было в той же IBM 360 на ранних этапах. Области сохранения данных, если нужно, размещались рядом с функциями (подпрограммами). Сейчас это возможно на супермелких платформах (уровня AVR или ниже).
Живой пример на первое. Берём код (что-то такое чтобы не влезало в регистры):
Просим ассемблер (запускается на убунте на стандартном десктопе): /usr/bin/s390x-linux-gnu-gcc-9 -S -O t01.c
Смотрим выхлоп (урезаю кучу вычислений и комментирую)
Но это всё ещё позволяет рекурсию, конечно. Просто для иллюстрации, что стека тут в явном виде нет
(ничто не мешало r15 применить под что угодно другое).
Как это влияет на системное программирование — отдельный разговор — могу описать, если интересно.
C>Вот за это люблю С++: на одном ресурсе обсуждаешь что-то из стандарта, и тебе говорят про необязательное существование стека (я бы очень хотел взглянуть на эти платформы),
Тут может быть два разных случая:
1. Стека формально нет в архитектуре, но нет проблем его сэмулировать для языка типа C/C++.
Это, например, обыкновеннейшая System/Z, потомок IBM 360.
Стек для C и других подобных эмулируется через регистр 15.
2. Стека нет в архитектуре и ресурсы не позволяют сэмулировать его. Это вообще исключает рекурсию.
Из опыта — такое было в той же IBM 360 на ранних этапах. Области сохранения данных, если нужно, размещались рядом с функциями (подпрограммами). Сейчас это возможно на супермелких платформах (уровня AVR или ниже).
Живой пример на первое. Берём код (что-то такое чтобы не влезало в регистры):
#include <stdio.h>
struct result { int x, y, z; };
struct result moo(int a, int b, int c, int d, int e, int f, int g, int h) {
struct result r;
r.x = a*b + c*d + e*f + g*h; r.y = a*c + b*d + e*g + f*h;
r.z = a*e + b*f + c*g + d*h;
printf("x=%d y=%d z=%d\n", r.x, r.y, r.z); return r;
}Просим ассемблер (запускается на убунте на стандартном десктопе): /usr/bin/s390x-linux-gnu-gcc-9 -S -O t01.c
Смотрим выхлоп (урезаю кучу вычислений и комментирую)
moo:
; сохранили callee-saved регистры (включая адрес возврата) скопом в стеке
stmg %r6,%r15,48(%r15)
lay %r15,-160(%r15) ; зарезервировали 160 байт в стеке
lgr %r8,%r2 ; адрес структуры возврата - первый скрытый аргумент
lr %r9,%r3 ; a
msr %r9,%r4 ; b
lr %r1,%r5 ; c
msr %r1,%r6 ; d
ar %r9,%r1
l %r1,324(%r15) ; e (уже не влез в первые 6 регистров, лежит в стеке)
ms %r1,332(%r15) ; f (аналогично)
...
; вызвали printf(), адрес возврата помещён в r14 (не на стек, это вам не x86)
brasl %r14,__printf_chk@PLT
...
lmg %r6,%r15,208(%r15) ; восстановили регистры скопом
br %r14 ; BR 14 - древний мем, все давно забылиНо это всё ещё позволяет рекурсию, конечно. Просто для иллюстрации, что стека тут в явном виде нет
(ничто не мешало r15 применить под что угодно другое).
Как это влияет на системное программирование — отдельный разговор — могу описать, если интересно.
Re[3]: Почему нет принудительного TCO?
Здравствуйте, cppguard, Вы писали:
C>Вот за это люблю С++: на одном ресурсе обсуждаешь что-то из стандарта, и тебе говорят про необязательное существование стека (я бы очень хотел взглянуть на эти платформы),
Тут может быть два разных случая:
1. Стека формально нет в архитектуре, но нет проблем его сэмулировать для языка типа C/C++.
Это, например, обыкновеннейшая System/Z, потомок IBM 360. Стек для C и других подобных эмулируется через регистр 15.
Это новомодный RISC-V. Тоже, стек существует только в рамках соглашения (x2 — указатель стека, x1 — регистр адреса возврата), ну и сжатые инструкции и хинты реализации заточены под это (хотите другие — не пользуйтесь сжатыми и будете иметь проблемы секьюрити, где они есть).
2. Стека нет в архитектуре и ресурсы не позволяют сэмулировать его. Это вообще исключает рекурсию.
Из опыта — такое было в той же IBM 360 на ранних этапах. Области сохранения данных, если нужно, размещались рядом с функциями (подпрограммами). Сейчас это возможно на супермелких платформах (уровня AVR или ниже).
-----
Живой пример на первое. Берём код (что-то такое чтобы не влезало в регистры):
Просим ассемблер (запускается на убунте на стандартном десктопе): /usr/bin/s390x-linux-gnu-gcc-9 -S -O t01.c
Смотрим выхлоп (урезаю кучу вычислений и комментирую)
Но это всё ещё позволяет рекурсию, конечно. Просто для иллюстрации, что стека тут в явном виде нет
(ничто не мешало r15 применить под что угодно другое).
Как это влияет на системное программирование — отдельный разговор — могу описать, если интересно.
C>Вот за это люблю С++: на одном ресурсе обсуждаешь что-то из стандарта, и тебе говорят про необязательное существование стека (я бы очень хотел взглянуть на эти платформы),
Тут может быть два разных случая:
1. Стека формально нет в архитектуре, но нет проблем его сэмулировать для языка типа C/C++.
Это, например, обыкновеннейшая System/Z, потомок IBM 360. Стек для C и других подобных эмулируется через регистр 15.
Это новомодный RISC-V. Тоже, стек существует только в рамках соглашения (x2 — указатель стека, x1 — регистр адреса возврата), ну и сжатые инструкции и хинты реализации заточены под это (хотите другие — не пользуйтесь сжатыми и будете иметь проблемы секьюрити, где они есть).
2. Стека нет в архитектуре и ресурсы не позволяют сэмулировать его. Это вообще исключает рекурсию.
Из опыта — такое было в той же IBM 360 на ранних этапах. Области сохранения данных, если нужно, размещались рядом с функциями (подпрограммами). Сейчас это возможно на супермелких платформах (уровня AVR или ниже).
-----
Живой пример на первое. Берём код (что-то такое чтобы не влезало в регистры):
#include <stdio.h>
struct result { int x, y, z; };
struct result moo(int a, int b, int c, int d, int e, int f, int g, int h) {
struct result r;
r.x = a*b + c*d + e*f + g*h; r.y = a*c + b*d + e*g + f*h;
r.z = a*e + b*f + c*g + d*h;
printf("x=%d y=%d z=%d\n", r.x, r.y, r.z); return r;
}Просим ассемблер (запускается на убунте на стандартном десктопе): /usr/bin/s390x-linux-gnu-gcc-9 -S -O t01.c
Смотрим выхлоп (урезаю кучу вычислений и комментирую)
moo:
; сохранили callee-saved регистры (включая адрес возврата) скопом в стеке
stmg %r6,%r15,48(%r15)
lay %r15,-160(%r15) ; зарезервировали 160 байт в стеке
lgr %r8,%r2 ; адрес структуры возврата - первый скрытый аргумент
lr %r9,%r3 ; a
msr %r9,%r4 ; b
lr %r1,%r5 ; c
msr %r1,%r6 ; d
ar %r9,%r1
l %r1,324(%r15) ; e (уже не влез в первые 6 регистров, лежит в стеке)
ms %r1,332(%r15) ; f (аналогично)
...
; вызвали printf(), адрес возврата помещён в r14 (не на стек, это вам не x86)
brasl %r14,__printf_chk@PLT
...
lmg %r6,%r15,208(%r15) ; восстановили регистры скопом
br %r14 ; BR 14 - древний мем, все давно забылиНо это всё ещё позволяет рекурсию, конечно. Просто для иллюстрации, что стека тут в явном виде нет
(ничто не мешало r15 применить под что угодно другое).
Как это влияет на системное программирование — отдельный разговор — могу описать, если интересно.