Сразу задам вопрос, кто-нибудь знает толковую книжку с хорошей теорией генерации кода из SSA?
'Advanced Compiler Design and Implementation'
Автор: Steven Muchnick. Издание охватывает широкий спектр тем, связанных с дизайном и реализацией компиляторов, с акцентом на оптимизацию и использование SSA.
'Modern Compiler Implementation'
Потом еще переключение режимов нормализации АЛУ тоже наверно занимает время. Общем модель процессора получается весьма специфическая, нужна хорошая теория под это, кто знает?
Соглашение о вызовах тоже влияет на кодогерерацию и оптимизацию, но это большая тема и я хотел бы все обсуждения относительно аллокации регистров, scheduling и кодогенерации вести здесь.
Сразу задам вопрос, кто-нибудь знает толковую книжку с хорошей теорией генерации кода из SSA?
On Sunday, March 2, 2025 at 4:57:42 AM UTC-8 oxy...@gmail.com wrote:Сразу задам вопрос, кто-нибудь знает толковую книжку с хорошей теорией генерации кода из SSA?Я озадачивался этим вопросом в 1987 году, когда начинал возиться с Си-компилятором для БЭСМ. Опытные товарищи указывали на книжку Ахо-Ульмана. Тогдашнее издание было слишком теоретичное. Современное получше вроде.
В результате я изучал кодогенерацию по исходникам компилятора PCC и статье Стива Джонсона:С тех пор мне встречалось много литературы по компиляторам. Но вот так чтобы прочитать умную книжку, всё понять, сесть и написать кодогенератор - таких книг нету, увы. Есть Си-компиляторы, исходники которых могут служить неплохим пособием. К примеру: https://github.com/alexfru/SmallerC--Сергей
--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/bc6e7892-22d0-4fbe-9eac-a022e6f34aa0n%40googlegroups.com.
Я-то предполагал, что The Dragon Book - настольная книга каждого компиляторщика по умолчанию, так что её рекомендовать не стал. Но я её давно читал и не помню, есть ли там что-то именно про генерацию кода из SSA.
Here’s a curated list of resources and literature on translating SSA (Static Single Assignment) form to CPU instruction sets, parameterized compilers, and related topics. These range from foundational papers to practical guides used in modern compiler design.
Foundational Papers on SSAThese should give you a solid mix of theory, practice, and modern implementation details.
Я спросил у grok.com про литературу по SSA трансляции.
GCC для PDP-10 здесь: http://pdp10.nocrew.org/gcc/download/
CHAR_BIT == 48 сделать несложно, но это будет игрушечная реализация (32К получившихся "байтов" - не для реальной работы).
При таком подходе сляпать самый простой самокомпилирующийся компилятор можно и из https://github.com/rswier/c4/
Вместо байткода будет шитый код, а некоторые операции даже нативно в две команды поместятся
суббота, 15 марта 2025 г. в 17:02:16 UTC+1, Leo B.:GCC для PDP-10 здесь: http://pdp10.nocrew.org/gcc/download/Я не нашел текстов С программ, которые бы компилировались этим GCC для PDP10. На сколько они портабельно выглядят. Вот тексты порисованных под PDP10 программ на С дали бы какие-то идеи.
CHAR_BIT == 48 сделать несложно, но это будет игрушечная реализация (32К получившихся "байтов" - не для реальной работы).Но не CHAR_BIT == 48 единым... __attribute__(packed, aligned(8)) char, компилятор бы упаковывал бы до 6-и ASCII символов в слово, детали можно скрыть в puts() и printf() - реализовать можно как в ФОРТРАНе и ПАСКАЛе. Но для этого нужен свой фронтенд написать, править clang для меня не вариант и по времени и хотяб потому что это С++.
При таком подходе сляпать самый простой самокомпилирующийся компилятор можно и из https://github.com/rswier/c4/
Вместо байткода будет шитый код, а некоторые операции даже нативно в две команды поместятсяВот интересная ссылочка! это прям черновик для фронтенда, который можно перевести на LLVM бекенд чуть не за выходные.Только вас не смущает лицензия GPL 2.0? и dispak и dubna выпущены под MIT лицензией?
Если я возьму С4 за основу, никаких частей из них я не буду иметь права брать :(
.Только вас не смущает лицензия GPL 2.0? и dispak и dubna выпущены под MIT лицензией?Если я возьму С4 за основу, никаких частей из них я не буду иметь права брать :(Как раз имеете (впрочем, не то чтобы в компиляторе была нужда в коде из dispak или dubna).MIT - более свободная лицензия, чем GPL. Это наоборот, если что-то GPL взять и использовать в изначально MIT-лицензированном софте,это его заражает GPL-лицензией.
Leo
суббота, 15 марта 2025 г. в 17:02:16 UTC+1, Leo B.:GCC для PDP-10 здесь: http://pdp10.nocrew.org/gcc/download/Я не нашел текстов С программ, которые бы компилировались этим GCC для PDP10. На сколько они портабельно выглядят. Вот тексты порисованных под PDP10 программ на С дали бы какие-то идеи.
CHAR_BIT == 48 сделать несложно, но это будет игрушечная реализация (32К получившихся "байтов" - не для реальной работы).Но не CHAR_BIT == 48 единым... __attribute__(packed, aligned(8)) char, компилятор бы упаковывал бы до 6-и ASCII символов в слово, детали можно скрыть в puts() и printf() - реализовать можно как в ФОРТРАНе и ПАСКАЛе. Но для этого нужен свой фронтенд написать, править clang для меня не вариант и по времени и хотяб потому что это С++.Ну так Паскаль уже ровно так и делает, если объявить packed array of char, тем и ценен. По умолчанию unpacked array of char держат по одному символу в слове для скорости.
При таком подходе сляпать самый простой самокомпилирующийся компилятор можно и из https://github.com/rswier/c4/
Вместо байткода будет шитый код, а некоторые операции даже нативно в две команды поместятсяВот интересная ссылочка! это прям черновик для фронтенда, который можно перевести на LLVM бекенд чуть не за выходные.Только вас не смущает лицензия GPL 2.0? и dispak и dubna выпущены под MIT лицензией?Если я возьму С4 за основу, никаких частей из них я не буду иметь права брать :(Как раз имеете (впрочем, не то чтобы в компиляторе была нужда в коде из dispak или dubna).MIT - более свободная лицензия, чем GPL. Это наоборот, если что-то GPL взять и использовать в изначально MIT-лицензированном софте,это его заражает GPL-лицензией.
Leo
CHAR_BIT == 48 сделать несложно, но это будет игрушечная реализация (32К получившихся "байтов" - не для реальной работы).Но не CHAR_BIT == 48 единым... __attribute__(packed, aligned(8)) char, компилятор бы упаковывал бы до 6-и ASCII символов в слово, детали можно скрыть в puts() и printf() - реализовать можно как в ФОРТРАНе и ПАСКАЛе. Но для этого нужен свой фронтенд написать, править clang для меня не вариант и по времени и хотяб потому что это С++.Ну так Паскаль уже ровно так и делает, если объявить packed array of char, тем и ценен. По умолчанию unpacked array of char держат по одному символу в слове для скорости.
Leo
Ну так Паскаль уже ровно так и делает, если объявить packed array of char, тем и ценен. По умолчанию unpacked array of char держат по одному символу в слове для скорости.Вот это пеня и подкупает, общем есть в С стандартные возможности, которые можно применить "нестандартно". Но для этого надо и свой фронт-енд иметь. Просто подправить какойнибудь tcc или даже c4.Только вот как быть с лицензиями.
MIT - более свободная лицензия, чем GPL. Это наоборот, если что-то GPL взять и использовать в изначально MIT-лицензированном софте,это его заражает GPL-лицензией.Тоесть Вы не возражаете, если кто-то, или я, возмет надергает структур из dispack для бекенда, и распространит это как GPL???
Ну конечно, заголовки с авторством сохраняются и ка-бы требования MIT удовлетворены.Но дальше все будут _обязаны_ публиковать исходники если что-то там поменяли, и тут адвокаты MIT не захотят ли на этом заработать?
У меня в голове не укладывается, если "так можно было" то почему Линукс не возмет пол ядра от BSD и багов будет в 2 раза меньше :)
У меня есть небольшой прогресс, хотя при правках AST каждый раз разваливается, но мало-мальски заработал Constant-propagaton.И вот возник вопрос как писать циклы. Я почти всегда писал так:for (int i = ARRAY_SIZE(ary); i--;)ary[i] = i;
Вопрос, как "понятней" всего писать для БЭСМ6?
Решил открыть отдельную тему по кодогенерации для нового оптимизирующего компилятора. Тема по формату вызовов https://groups.google.com/g/besm6/c/LJ91waEdhzE/m/USweH2PIAgAJ так и остается, там будем обсуждать только соглашения о вызовах какие были и какие будут, чтоб не захламлять.
В теме "БЭСМ6 программирование на Паскале" всплыли интересные нюансы в генерации объектных файлов.Что все глобальные переменные программы на паскале попадают в COMMON блок P/1D. COMMON блок это не просто сегмент куда линковщик/загрузчик добавляет данные из всех линкуемых модулей. Это секция в памяти как-бы проецируемая во все модули, которые на нее ссылаются и соответсвенно разделяют все данные от начала и до конца. Главное отличие, что все данные/сруктуры объявленный в COMMON блок должны совпадать, иначе будет каша при изменениях.Мне кажется это вытекает из того, что в формате объектного файла БЭСМ6 можно экспортировать всего 19 сущностей, было-бы больше - можно было бы каждую переменную экспортировать под отдельным именем и загрузчик все ссылки правильно настроил.
Еще есть особенность Паскаля - вложенные функции, что существенно облегчает ситуацию, конечно возможны и другие варианты, но с моей точки зрения именно вложенные функции позволяют проблему с наложением/согласованием глобальных данных в COMMON блоке P/1D решать кардинально - вообще не объявлять глобальных переменных в PROGRAMM, а объявлять их только во вложенных функциях.
Свой компилятор С мне хотелось бы реализовать как компилятор для системы, и считаю, что вложенные функции так должноы поддерживаться как расширение GCC, они позволяют писать более компактный код и быстрее вызывать вложенные функции не "пропихивая" через стек все нужные переменные. Но это отхождение от стандарта, и хотелось бы дать пользователям по умолчанию компилировать код обычных POSIX утилит с глобальными переменными и избегать проблем с конфликтом в P/1D.
Я сторонник стандартов, есть желание сделать код сгенерированный С 100% совместимый с Паскалем и Фортраном.Не прочь использовать даже библиотечные функции Паскаля, если предполагается 100% совместимость, то код будет часто работать совместно, есть смысл использовать те-же функции и константы в P/1D - экономия памяти. Кстати как Вы считаете их эффективность? Я полагаю очень хороший, а если что то можно и оптимизировать где-это, от этого выиграют оба языка.
Но нехотелось бы ограничивать пользователей С в плане глобальных переменных.Есть готовое решение проблемы глобальных переменных в С, поделитесь?
On Friday, April 4, 2025 at 12:31:32 PM UTC-7 oxy...@gmail.com wrote:В теме "БЭСМ6 программирование на Паскале" всплыли интересные нюансы в генерации объектных файлов.Что все глобальные переменные программы на паскале попадают в COMMON блок P/1D. COMMON блок это не просто сегмент куда линковщик/загрузчик добавляет данные из всех линкуемых модулей. Это секция в памяти как-бы проецируемая во все модули, которые на нее ссылаются и соответсвенно разделяют все данные от начала и до конца. Главное отличие, что все данные/сруктуры объявленный в COMMON блок должны совпадать, иначе будет каша при изменениях.Мне кажется это вытекает из того, что в формате объектного файла БЭСМ6 можно экспортировать всего 19 сущностей, было-бы больше - можно было бы каждую переменную экспортировать под отдельным именем и загрузчик все ссылки правильно настроил.
Нет, экспортируемыми считаются только входы в процедуры. Коммон-блоки, как и вызываемые внешние процедуры - "импортируемые", их могло быть много. Проблема в том, что адрес каждого отдельного коммон-блока мог быть произвольным, поэтомув отсутствие оптимизаций или глобального базирования все обращения к нему должны были делаться через UTC. А адрес P/1D как ставился на регистр 1 в начале программы, так на него всегда можно было рассчитывать.
Еще есть особенность Паскаля - вложенные функции, что существенно облегчает ситуацию, конечно возможны и другие варианты, но с моей точки зрения именно вложенные функции позволяют проблему с наложением/согласованием глобальных данных в COMMON блоке P/1D решать кардинально - вообще не объявлять глобальных переменных в PROGRAMM, а объявлять их только во вложенных функциях.Тогда они в стеке будут и не будут сохраняться между вызовами. Если хочется сделать что-то типа датчика случайных чисел, придется делать коммон-блок.Свой компилятор С мне хотелось бы реализовать как компилятор для системы, и считаю, что вложенные функции так должноы поддерживаться как расширение GCC, они позволяют писать более компактный код и быстрее вызывать вложенные функции не "пропихивая" через стек все нужные переменные. Но это отхождение от стандарта, и хотелось бы дать пользователям по умолчанию компилировать код обычных POSIX утилит с глобальными переменными и избегать проблем с конфликтом в P/1D.Каждую глобальную переменную, скомпилированную с "external linkage" придется иметь в отдельном блоке. Все static переменные, объявленные в файле, можно держать в одном блоке, адрес которого в начале всех процедур файла можно ставить на регистр.
В компиляторе, который я медленно и постепенно делаю из Паскаля, я склоняюсь к отказу от вложенных функций ради упрощения компилятора. Если реализовать регистровые указатели в качестве формальных параметров процедур, это будет практически эквивалентно по эффективности, но более общо.
Я сторонник стандартов, есть желание сделать код сгенерированный С 100% совместимый с Паскалем и Фортраном.Не прочь использовать даже библиотечные функции Паскаля, если предполагается 100% совместимость, то код будет часто работать совместно, есть смысл использовать те-же функции и константы в P/1D - экономия памяти. Кстати как Вы считаете их эффективность? Я полагаю очень хороший, а если что то можно и оптимизировать где-это, от этого выиграют оба языка.Безусловно, если желаемая функциональность уже есть, почему бы не использовать. Насчет качества исполнения, правда, есть сомнения, судя по тому же P/WI, который был написан некомпетентно.
Но нехотелось бы ограничивать пользователей С в плане глобальных переменных.Есть готовое решение проблемы глобальных переменных в С, поделитесь?Более или менее готовое решение, которое позволит иметь каждую глобальную переменную в отдельном коммон-блоке без затрат на UTC - глобальное базирование. Даже если делать вложенные процедуры, то достаточно будет ограничить глубину вложенности не 6, как сейчас в Паскале, а 3 или 4, и регистров должно хватить.
Leo
(*=p-,t-,s8,y+*)
program exPointers(output);
var
number: integer;
iptr: @integer;
y: @integer;
begin
iptr := nil;
y := ref(iptr);
writeln('the vaule of iptr is ', iptr, y^);
end.
ТНЕ VАULЕ ОF IРТR IS 0000000000074000 30720
КОНЕЦ ЗАДАЧИ
00411: 00 074 0000 *74
runtime error: negation of 1 cannot be represented in type 'unsigned int'
12 апр. 2025 г., в 12:19, Alex Loktionoff <oxy...@gmail.com> написал(а):
Вызывает интерес и такой еще разрез: NULL/NIL.Очень хотелось бы сохранить для С NULL == 0, но и не потерять совместимости с Паскалем.Интересно зачем в Паскале приняли тако странный NIL?
С С-шным NULL библиотечные P/xx функции работать не будут и придется писать свои?(*=p-,t-,s8,y+*)program exPointers(output);varnumber: integer;iptr: @integer;y: @integer;beginiptr := nil;y := ref(iptr);
writeln('the vaule of iptr is ', iptr, y^);end....ТНЕ VАULЕ ОF IРТR IS 0000000000074000 30720КОНЕЦ ЗАДАЧИ00411: 00 074 0000 *74воскресенье, 2 марта 2025 г. в 13:57:42 UTC+1, Alex Loktionoff:Решил открыть отдельную тему по кодогенерации для нового оптимизирующего компилятора. Тема по формату вызовов https://groups.google.com/g/besm6/c/LJ91waEdhzE/m/USweH2PIAgAJ так и остается, там будем обсуждать только соглашения о вызовах какие были и какие будут, чтоб не захламлять.
--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/217a92cb-20ee-4435-85a8-addcc3b53831n%40googlegroups.com.
13 апр. 2025 г., в 01:16, Alex Loktionoff <oxy...@gmail.com> написал(а):
Пришла беда, откуда не ждали, ubsan ругается на for (unsigned int i = -count; i++; ) {runtime error: negation of 1 cannot be represented in type 'unsigned int'Это для меня выглядит странно, потому как если я говорю i = 0 - count; То я хочу получить такое i, чтоб i + count == 0.
Пока пришлось заменить все на int, но при это теряется половина диапазона цикла.Что делать? По моему ubsan неправ с "Unsigned integer overflow" и надо просто его отключить?
--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/48898ab6-4b29-4fb2-8d5b-a13e03ac62d6n%40googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/D575907C-F46B-480E-AAE6-FAE18345C202%40gmail.com.
13 апр. 2025 г., в 01:16, Alex Loktionoff <oxy...@gmail.com> написал(а):Пришла беда, откуда не ждали, ubsan ругается на for (unsigned int i = -count; i++; ) {runtime error: negation of 1 cannot be represented in type 'unsigned int'Это для меня выглядит странно, потому как если я говорю i = 0 - count; То я хочу получить такое i, чтоб i + count == 0.и какое же i в диапазоне unsigned int (!) сложении (!) с count даст 0 ?или подразумевается, что count принципиально отрицательное?автоматическое преобразование int в unsigned int и обратно хотелось?я б на месте компилятора озадачился, это не всегда можно делать без искажения смысла.Пока пришлось заменить все на int, но при это теряется половина диапазона цикла.Что делать? По моему ubsan неправ с "Unsigned integer overflow" и надо просто его отключить?я - на его стороне.
он не зря требует, чтобы извращение было описано явно.for (unsigned int i = (unsigned int) (-count); i++) {
(lldb) r
Process 86552 launched: '/Users/oxy/myprojects/C/forwat/forwat.exe' (x86_64)
Process 86552 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = Unsigned integer overflow
frame #0: 0x00000001003555d0 libclang_rt.ubsan_osx_dynamic.dylib`__ubsan_on_report
libclang_rt.ubsan_osx_dynamic.dylib`__ubsan_on_report:
-> 0x1003555d0 <+0>: pushq %rbp
0x1003555d1 <+1>: movq %rsp, %rbp
0x1003555d4 <+4>: popq %rbp
0x1003555d5 <+5>: retq
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = Unsigned integer overflow
* frame #0: 0x00000001003555d0 libclang_rt.ubsan_osx_dynamic.dylib`__ubsan_on_report
frame #1: 0x000000010034f9cd libclang_rt.ubsan_osx_dynamic.dylib`__ubsan::Diag::~Diag() + 237
frame #2: 0x000000010035219a libclang_rt.ubsan_osx_dynamic.dylib`handleNegateOverflowImpl(__ubsan::OverflowData*, unsigned long, __ubsan::ReportOptions) + 602
frame #3: 0x0000000100351f34 libclang_rt.ubsan_osx_dynamic.dylib`__ubsan_handle_negate_overflow + 52
frame #4: 0x0000000100005d2e forwat.exe`me_cod_unop_create_load(ptr=0x0000000100da0340, typr=0x0000000100da0320, token=0x00000001000163e8) at me_ast.h:1328:21
frame #5: 0x0000000100008413 forwat.exe`main at main.c:108:26
frame #6: 0x000000010002552e dyld`start + 462
(lldb) f 4
frame #4: 0x0000000100005d2e forwat.exe`me_cod_unop_create_load(ptr=0x0000000100da0340, typr=0x0000000100da0320, token=0x00000001000163e8) at me_ast.h:1328:21
1325 me_bld *bld = me_ctx_cur.bld;
1326 me_ast_node_kv *p = bld->var_hash;
1327
-> 1328 for (uint i = (uint)-bld->var_count; i++; ++p)
1329 if (p->k == ptr) {
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/8d4b5a0a-1bc7-4ae4-88cb-0a75312416ccn%40googlegroups.com.
Как же обрабатывать массивы свыше 16К на С?вот код который мне кажется я где-то видел:3, VTM , -(SIZ-1)LOOP : 3, ATX , ARY + (SIZ-1)3, VLM , LOOPи теоретически может, а как такое написать на С?
Вот именно, что компиляторы выросли, а ubsan - не очень, и видит UB там, где его в помине нет. Сложение двух unsigned - по определению по модулю степени двойки.
Leo
Пишу я значит свой back-end, примем начал основательно с нижней части middle-end.У меня уже мало-мальски формируется AST, если точнее это не AST, а более приземленное /* возможно циклическое*/ графовое представление с зависимостями и basic-block-ами - нечто среднее между LLVM IR и LLVM MIR. И вот как раз на подходе к back-end впал я в ступор.Принимаю решение реализовывать кодогенерацию a-la GlobalISel а не SelectionDAG так как SelectionDAG уже показало что ни чем не лучше GlobalISel по качеству генерируемого кода, а по скорости уступает раза в 2, еще SelectionDAG подразумевает создание кучи дополнительных структур и форматов, что неэффективно а для БЭСМ6 вообще некрасиво до невозможности.Еще GlobalISel можно реализовывать постепенно, что весьма немаловажно для любительской реализации, а с SelectionDAG похоже, чтоб что-то заработало надо написать ~%80. - OkНо все-равно вопрос, нужно ли создавать еще MIR представление /*отдельные структуры и функции по работе с ними*/??? Очень не хотелось бы! Что бросается в глаза это разница в оформлении параметров функции ну и что в MIR MachineInstr G_ADD например явно указывается регистр результата, в IR Value сама инструкция это уже 'виртуальный' регистр. Первое - а почему-бы кодогенератор при lowering не взять и сгенерировать нужные команды LLVMGetParam().MachineInstr и так занимает 40-100 байт, у меня me_ast_node занимает 16, хотелось бы запихнуть
В LLVM принято постепенное lowering MIR инструкций, для максимальной оптимизации это необходимость? Или это артефакт педализации.
tdd-test % make clean debug run
rm -rf *.dSYM
rm -f *.ll *.o *.exe *.map *.dsk a.out
gcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DDEBUG -O1 -ggdb -fsanitize=signed-integer-overflow -fsanitize=unsigned-integer-overflow -fsanitize=undefined -fsanitize=address -I/usr/local/opt/openjdk/include -c -o tst-ilist.o tst-ilist.c
gcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DDEBUG -O1 -ggdb -fsanitize=signed-integer-overflow -fsanitize=unsigned-integer-overflow -fsanitize=undefined -fsanitize=address -L ../lib -flto -o tdd-test.exe tst-ilist.o
ld: warning: directory not found for option '-L../lib'
./tdd-test.exe
tdd-test.exe(2569,0x1091a6600) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
Test list empty... [ OK ]
Test list singular... [ OK ]
Test list dual... [ OK ]
Test list complex... [ OK ]
Test list foreach... [ OK ]
SUCCESS: No unit tests have failed.
tdd-test % make clean release run | head -20
rm -rf *.dSYM
rm -f *.ll *.o *.exe *.map *.dsk a.out
gcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DNDEBUG -O3 -I/usr/local/opt/openjdk/include -c -o tst-ilist.o tst-ilist.c
gcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DNDEBUG -O3 -L ../lib -flto -o tdd-test.exe tst-ilist.o
ld: warning: directory not found for option '-L../lib'
./tdd-test.exe
Test list empty... [ OK ]
Test list singular... [ OK ]
Test list dual... [ OK ]
Test list complex... [ FAILED ]
tst-ilist.c:82: &item3 == ilist_last_entry(&my_list, my_struct, list)... failed
tst-ilist.c:84: ilist_is_last(&item3.list, &my_list)... failed
tst-ilist.c:92: &item2 == ilist_next_entry(&item1, list)... failed
tst-ilist.c:95: &item2 == ilist_prev_entry(&item3, list)... failed
tst-ilist.c:96: &item1 == ilist_prev_entry(&item2, list)... failed
tst-ilist.c:97: &item0 == ilist_prev_entry(&item1, list)... failed
Test list foreach... [ FAILED ]
tst-ilist.c:123: seq_expected[5] == item->data;//1 == 32759... failed
tst-ilist.c:123: seq_expected[6] == item->data;//2 == 7... failed
tst-ilist.c:123: seq_expected[7] == item->data;//3 == 6... failed
tst-ilist.c:123: seq_expected[8] == item->data;//538976288 == 5... failed
причем если вместо short signed int я переопределяю #define ILIST_IDX_T int
то падает уже даже debug build и даже tcc X-|
ничего не понимаю...
tdd-test % export CC=tcc
tdd-test % make clean debug run | head -20
rm -rf *.dSYM
rm -f *.ll *.o *.exe *.map *.dsk a.out
tcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DDEBUG -O1 -ggdb -fsanitize=signed-integer-overflow -fsanitize=unsigned-integer-overflow -fsanitize=undefined -fsanitize=address -I/usr/local/opt/openjdk/include -c -o tst-ilist.o tst-ilist.c
tcc -Wno-language-extension-token -Wall -Wextra -Werror -pedantic -ffunction-sections -fvisibility=hidden -I ../include -DDEBUG -O1 -ggdb -fsanitize=signed-integer-overflow -fsanitize=unsigned-integer-overflow -fsanitize=undefined -fsanitize=address -L ../lib -flto -o tdd-test.exe tst-ilist.o
./tdd-test.exe
Test list empty... [ OK ]
Test list singular... [ OK ]
Test list dual... [ FAILED ]
tst-ilist.c:56: ilist_is_last(&item2.list, &my_list)... failed
tst-ilist.c:57: &item2 == ilist_next_entry(&item1, list)... failed
tst-ilist.c:58: &item1 == ilist_prev_entry(&item2, list)... failed
Test list complex... [ FAILED ]
tst-ilist.c:83: &item3 == ilist_last_entry(&my_list, my_struct, list)... failed
tst-ilist.c:85: ilist_is_last(&item3.list, &my_list)... failed
tst-ilist.c:92: &item1 == ilist_next_entry(&item0, list)... failed
tst-ilist.c:93: &item2 == ilist_next_entry(&item1, list)... failed
tst-ilist.c:94: &item3 == ilist_next_entry(&item2, list)... failed
tst-ilist.c:96: &item2 == ilist_prev_entry(&item3, list)... failed
tst-ilist.c:97: &item1 == ilist_prev_entry(&item2, list)... failed
tst-ilist.c:98: &item0 == ilist_prev_entry(&item1, list)... failed
воскресенье, 2 марта 2025 г. в 13:57:42 UTC+1, Alex Loktionoff:
Решил открыть отдельную тему по кодогенерации для нового оптимизирующего компилятора.
Наступил я на какие-то UB грабли в С. Прошу помощи зала!
--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/e0d1355b-02a7-46cd-aab1-21fc5f97a78cn%40googlegroups.com.
On Thu, Apr 17, 2025 at 2:09 PM Alex Loktionoff <oxy...@gmail.com> wrote:Наступил я на какие-то UB грабли в С. Прошу помощи зала!
воскресенье, 2 марта 2025 г. в 13:57:42 UTC+1, Alex Loktionoff:
Решил открыть отдельную тему по кодогенерации для нового оптимизирующего компилятора....
Помогу чем могу. Я попросил Грока сгенерить юнит тесты для этого ilist. Результат сложил здесь: github.com/sergev/test-ilist. Подробности смотрите README. Тесты проходят на Линуксе но падают на маке. Разная политика выделения памяти.Проблема в том, что в функции ilist_add_() делается вычитание указателей, и результат запихивается в short int. В молчаливом предположении, что элементы списка находятся в памяти относительно близко, в пределах 32к элементов. Это предположение в общем случае неверно.
--СергейOn Thursday, April 17, 2025 at 2:09:48 PM UTC-7 oxy...@gmail.com wrote:
Наступил я на какие-то UB грабли в С. Прошу помощи зала!Для компилятора написал компактный двусвязный список, который вместо полноразмерных указателей использует короткие относительные индексы. И... все работает только до уровни оптимизации -O2 и в gcc и в clang /*tcc естественно работает всегда*/Причем вывод одинаковый и в gcc и clang, что кабы намекает что это не баг а какая-то фича :-/Это меня тормозит в написании back-end ну и понять хочу тоже, чего я до сих пор не понимаю в С, если немого написать двусвязный список :(
среда, 7 мая 2025 г. в 00:25:01 UTC+2, serge.v...@gmail.com:Помогу чем могу. Я попросил Грока сгенерить юнит тесты для этого ilist. Результат сложил здесь: github.com/sergev/test-ilist. Подробности смотрите README. Тесты проходят на Линуксе но падают на маке. Разная политика выделения памяти.Проблема в том, что в функции ilist_add_() делается вычитание указателей, и результат запихивается в short int. В молчаливом предположении, что элементы списка находятся в памяти относительно близко, в пределах 32к элементов. Это предположение в общем случае неверно.В общем случае неверно, но список как раз для конкретного - когда все лежит рядом.Грок сгенерировал неподходящие fixture.Удалось ли понять причину почему все разваливается при использовании long вместо short?
--Сергей
суббота, 10 мая 2025 г. в 19:19:13 UTC+2, Alex Loktionoff:
Удалось ли понять причину почему все разваливается при использовании long вместо short?
Мне кажется что первый в жизни я нарвался на pointer provenance