Я её поддержал на уровне "если RTN после AP, заменить на TAP". Правда, при это нужно было проверить, что рекурсивный вызов - строго в последней ветке if-ветвления. Ну, проверил в fold/while что это так, и делал всё через fold.
def fix_tail_call(code): for i in xrange(len(code)-1): if (code[i][0] == 'AP' and code[i+1][0] == 'RTN'): code[i] = ['TAP'] + code[i][1:] # leave 'RTN' in code, because it can be target of jump, # and avoid remapping of code offsets
В субботу grep-z точно так же попытался сделать, но как раз наткнулся на баг с ветвлением и откатил коммит :) А потом ему пришлось убежать по делам и весь процесс как-то забылся, потому что оно как-то и так на тот момент работало нормально :)
Можно проверять все после AP: если там только JOIN и другие инструкции, которые не трогают стек, то можно спокойно называть AP хвостово-рекурсивным и на дамп в AP ничего не класть (правда, еще нужно почистить все, что туда могли положить JOINы).
Для практики, чтобы работали обе ветки if - надо проверить ещё проверить развилки jump:
function_C: jump_if_cond branch call A -это тоже tail call! jump done хотя дальше что-то непонятное branch: call B done: ret
Я подозреваю, надо это делать не в результирующем ASM, а ещё пока у нас есть дерево (defun (...) ( .... цепочка if и cond .... ( (вызов функции) ).... )
> Надо было с первого же дня написать симулятор игры. Спорный момент - можно фиксать тонкие различия аж неделю, а потом напороться на то, что у организаторов свои оригинальные баги.
Я вообще FireFox использую, но этот эмулятор запускал в хроме с одним табом, это его ускорило в два раза. Ещё убрал перерисовку и апдейт DOM-дерева на каждом шаге, перерисовывал только через 10 шагов (правда, на сложных алгоритмах это уже не меняло ничего, bottleneck был уже не в отрисовке).
Ещё отладочная печать тормозила и всё вешала, поэтому перенаправил её в console.log
Ну, в итоге у нас klisp и был (в translate-walk), а все-остальное наворачивалось поверх макрами/функциями. Жаль только что до этого мы доперли слишком поздно :(
Кстати я тут запоздало ещё придумал, что можно было ваще не писать свои макры вроде OR. Достаточно было просто в translate-walk форму через macroexpand прогнать и транслировать уже результат:
CL-USER> (macroexpand '(when (and a b) (+ a b))) (IF (AND A B) (PROGN (+ A B)) NIL)
Comments 14
Я её поддержал на уровне "если RTN после AP, заменить на TAP".
Правда, при это нужно было проверить, что рекурсивный вызов - строго в последней ветке if-ветвления. Ну, проверил в fold/while что это так, и делал всё через fold.
def fix_tail_call(code):
for i in xrange(len(code)-1):
if (code[i][0] == 'AP' and code[i+1][0] == 'RTN'):
code[i] = ['TAP'] + code[i][1:]
# leave 'RTN' in code, because it can be target of jump,
# and avoid remapping of code offsets
Reply
Reply
Reply
function_C:
jump_if_cond branch
call A -это тоже tail call!
jump done хотя дальше что-то непонятное
branch:
call B
done:
ret
Я подозреваю, надо это делать не в результирующем ASM, а ещё пока у нас есть дерево
(defun (...) ( .... цепочка if и cond .... ( (вызов функции) ).... )
Reply
Спорный момент - можно фиксать тонкие различия аж неделю, а потом напороться на то, что у организаторов свои оригинальные баги.
Я вот так сделал - http://users.livejournal.com/_winnie/434449.html#comments
Reply
Reply
Ещё отладочная печать тормозила и всё вешала, поэтому перенаправил её в console.log
Reply
Reply
Reply
Reply
CL-USER> (macroexpand '(when (and a b) (+ a b)))
(IF (AND A B)
(PROGN (+ A B))
NIL)
Reply
Leave a comment