Forth http://www.fforum.winglion.ru/ |
|
Еще один способ работы с параметрами на стеке http://www.fforum.winglion.ru/viewtopic.php?f=2&t=3141 |
Страница 4 из 5 |
Автор: | chess [ Сб янв 01, 2022 17:29 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Victor__v писал(а): Как понимаю, Вы закидываете часть переменных выше вершины стека. Но как происходит контроль измерения глубины? При изменении этого самого стека? Ничего никуда не закидывается. В начале манипулятора просто отмечается с каким количеством верхних параметров на стеке будет работать данный манипулятор. Вот на стеке находятся 4 параметра: a b c d. Нам нужно оставить на стеке параметр а, а с параметрами b c d поработать. Мы пишем определение Код: : proba /[312M3m'1 ; что эквивалентно Код: : proba { b c d } b c MAX d MIN ; После исполнения слова proba на стеке останется два параметра Код: a и результат от Код: b c MAX d MIN Для управления стеком при компиляции используются стековые эффекты входящих в определение через двоеточие слов. Это технологический прием. Каждое слово форта имеет стековый эффект - величина на которую слово меняет глубину стека. Зная исходное состояние стека и стековые эффекты последовательно выполняемых слов, можно вычислять положение ячеек стека во время компиляции кода определения. Сложности при компиляции возникают для ветвлений, циклов, слов типа EXECUTE, LAMBDA{ и тому подобных. Для циклов я ввел правило - стековый эффект внутри цикла должен быть нулевым(аналогия со стеком возвратов). Для ветвлений ввел массив трасс ветвления, в который вписываются вычисляемые стековые эффекты каждой трассы. Для EXECUTE нужно менять структуру словарной статьи - вводить туда значение стекового эффекта (сейчас я привязку слов к их стековым эффектам реализовал в обход словарей). Пока такие слова ( типа EXECUTE) не использую. Немного оптимизировал код определений через двоеточие в части сокращения числа перестановок указателя стека. Убрал слово DUP как лишнее, так как вместо него можно просто написать номер верхней ячейки. С DROP такое не проходит, хотя запись, например ]3, означает, что если в стеке было 4 параметра, останется 3 нижних, верхнее удалится. Таким образом DROP тоже можно исключить. Вот еще некоторые соображения на примере: Код: \ площадь треугольника по Герону : S3 { a b c \ p } a b + c + 2 / TO p p a - p b - * p c - * p * sqrt ; SEE S3 : s3 /[312+3+(2)/41-42-*43-*4*q'1 ; SEE s3 : TST 100 0 DO 3 4 5 S3 DROP LOOP ; TIME : tst 100 0 DO 3 4 5 s3 DROP LOOP ; time CODE S3 621623 8945FC MOV FC [EBP] , EAX 621626 B80C000000 MOV EAX , # C 62162B 8D6DFC LEA EBP , FC [EBP] 62162E E8B11AF3FF CALL 5530E4 ( DRMOVE ) 621633 8945FC MOV FC [EBP] , EAX 621636 B801000000 MOV EAX , # 1 62163B 8D6DFC LEA EBP , FC [EBP] 62163E E8DD1BF3FF CALL 553220 ( (RALLOT) ) 621643 6810000000 PUSH , # 10 621648 6868325500 PUSH , # 553268 62164D 8945FC MOV FC [EBP] , EAX 621650 8B442414 MOV EAX , 14 [ESP] 621654 03442410 ADD EAX , 10 [ESP] 621658 0344240C ADD EAX , C [ESP] 62165C B902000000 MOV ECX , # 2 621661 99 CDQ 621662 F7F9 IDIV ECX 621664 89442408 MOV 8 [ESP] , EAX 621668 2B442414 SUB EAX , 14 [ESP] 62166C 8945F8 MOV F8 [EBP] , EAX 62166F 8B442408 MOV EAX , 8 [ESP] 621673 2B442410 SUB EAX , 10 [ESP] 621677 F76DF8 IMUL F8 [EBP] 62167A 8945F8 MOV F8 [EBP] , EAX 62167D 8B442408 MOV EAX , 8 [ESP] 621681 2B44240C SUB EAX , C [ESP] 621685 F76DF8 IMUL F8 [EBP] 621688 8945F8 MOV F8 [EBP] , EAX 62168B 8B442408 MOV EAX , 8 [ESP] 62168F F76DF8 IMUL F8 [EBP] 621692 8D6DFC LEA EBP , FC [EBP] 621695 E88D57FFFF CALL 616E27 ( sqrt ) 62169A C3 RET NEAR END-CODE ( 120 bytes, 33 instructions ) CODE s3 6216AB 8945FC MOV FC [EBP] , EAX 6216AE 8B4504 MOV EAX , 4 [EBP] 6216B1 034500 ADD EAX , 0 [EBP] 6216B4 0345FC ADD EAX , FC [EBP] 6216B7 8945F8 MOV F8 [EBP] , EAX 6216BA B802000000 MOV EAX , # 2 6216BF 8BC8 MOV ECX , EAX 6216C1 8B45F8 MOV EAX , F8 [EBP] 6216C4 99 CDQ 6216C5 F7F9 IDIV ECX 6216C7 8945F8 MOV F8 [EBP] , EAX 6216CA 2B4504 SUB EAX , 4 [EBP] 6216CD 8945F4 MOV F4 [EBP] , EAX 6216D0 8B45F8 MOV EAX , F8 [EBP] 6216D3 2B4500 SUB EAX , 0 [EBP] 6216D6 F76DF4 IMUL F4 [EBP] 6216D9 8945F4 MOV F4 [EBP] , EAX 6216DC 8B45F8 MOV EAX , F8 [EBP] 6216DF 2B45FC SUB EAX , FC [EBP] 6216E2 F76DF4 IMUL F4 [EBP] 6216E5 F76DF8 IMUL F8 [EBP] 6216E8 8D6DF8 LEA EBP , F8 [EBP] 6216EB E83757FFFF CALL 616E27 ( sqrt ) 6216F0 8D6D10 LEA EBP , 10 [EBP] 6216F3 C3 RET NEAR END-CODE ( 73 bytes, 25 instructions ) 2836 ns ( время TST) 1274 ns ( время tst) Вычисление на стеке в итоге помещает результат в конкретную ячейку, в качестве имени которой в дальнейших вычислениях используется номер этой ячейки. Необходимости в явном присвоении (как для локальных переменных в SPF - см. пример выше ) нет, что дополнительно повышает эффективность кода. Еще кое-что: Использование номеров ячеек в качестве имен локальных переменных вполне годится, потому, что внутри определения локальных переменных немного и наделять их каким особым смыслом нет необходимости. PS. С Новым Годом! |
Автор: | chess [ Ср май 18, 2022 22:21 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Вариант реализации локальных переменных без использования хипа и стека возвратов с использованием только стека параметров на основе выражений типа стексов. Этот вариант вполне подошел также и для Win64FasmForth ( 64-разрядная форт-система для Windows ) в качестве оптимизатора, которого в Win64FasmForth нет. Пример: Код: : S+ { a1 u1 a2 u2 \ a u } u1 u2 + DUP TO u ALLOCATE THROW TO a a1 a u1 MOVE a2 a u1 + u2 MOVE a u ; SEE S+ S" 123 " S" abc" S+ CR TYPE : s+ ( a1 u1 a2 u2 -- a u ) 4$24 + ALLOCATE THROW 5$152 MOVE 5|5243452 + 2|21 MOVE + ; SEE s+ S" 123 " S" abc" s+ CR TYPE CODE S+ 435F58 E8 4F 39 FD FF call $4098AC ( DUP ) 435F5D 48 B8 00 00 00 00 00 00 00 00 mov rax,$0 435F67 E8 CF 48 FD FF call $40A83B ( >R ) 435F6C E8 3B 39 FD FF call $4098AC ( DUP ) 435F71 48 B8 00 00 00 00 00 00 00 00 mov rax,$0 435F7B E8 BB 48 FD FF call $40A83B ( >R ) 435F80 E8 B6 48 FD FF call $40A83B ( >R ) 435F85 E8 B1 48 FD FF call $40A83B ( >R ) 435F8A E8 AC 48 FD FF call $40A83B ( >R ) 435F8F E8 A7 48 FD FF call $40A83B ( >R ) 435F94 E8 13 39 FD FF call $4098AC ( DUP ) 435F99 48 B8 30 00 00 00 00 00 00 00 mov rax,$30 435FA3 E8 93 48 FD FF call $40A83B ( >R ) 435FA8 E8 FF 38 FD FF call $4098AC ( DUP ) 435FAD 48 B8 8C BE 40 00 00 00 00 00 mov rax,$40BE8C 435FB7 E8 7F 48 FD FF call $40A83B ( >R ) 435FBC E8 EB 38 FD FF call $4098AC ( DUP ) 435FC1 48 B8 18 00 00 00 00 00 00 00 mov rax,$18 435FCB E8 B4 49 FD FF call $40A984 ( RP@ ) 435FD0 E8 6D 47 FD FF call $40A742 ( + ) 435FD5 E8 A0 3B FD FF call $409B7A ( @ ) 435FDA E8 CD 38 FD FF call $4098AC ( DUP ) 435FDF 48 B8 28 00 00 00 00 00 00 00 mov rax,$28 435FE9 E8 96 49 FD FF call $40A984 ( RP@ ) 435FEE E8 4F 47 FD FF call $40A742 ( + ) 435FF3 E8 82 3B FD FF call $409B7A ( @ ) 435FF8 E8 45 47 FD FF call $40A742 ( + ) 435FFD E8 AA 38 FD FF call $4098AC ( DUP ) 436002 E8 A5 38 FD FF call $4098AC ( DUP ) 436007 48 B8 38 00 00 00 00 00 00 00 mov rax,$38 436011 E8 6E 49 FD FF call $40A984 ( RP@ ) 436016 E8 27 47 FD FF call $40A742 ( + ) 43601B E8 3A 3C FD FF call $409C5A ( ! ) 436020 E8 BC 5C FD FF call $40BCE1 ( ALLOCATE ) 436025 E8 94 E7 FC FF call $4047BE ( THROW ) 43602A E8 7D 38 FD FF call $4098AC ( DUP ) 43602F 48 B8 30 00 00 00 00 00 00 00 mov rax,$30 436039 E8 46 49 FD FF call $40A984 ( RP@ ) 43603E E8 FF 46 FD FF call $40A742 ( + ) 436043 E8 12 3C FD FF call $409C5A ( ! ) 436048 E8 5F 38 FD FF call $4098AC ( DUP ) 43604D 48 B8 10 00 00 00 00 00 00 00 mov rax,$10 436057 E8 28 49 FD FF call $40A984 ( RP@ ) 43605C E8 E1 46 FD FF call $40A742 ( + ) 436061 E8 14 3B FD FF call $409B7A ( @ ) 436066 E8 41 38 FD FF call $4098AC ( DUP ) 43606B 48 B8 30 00 00 00 00 00 00 00 mov rax,$30 436075 E8 0A 49 FD FF call $40A984 ( RP@ ) 43607A E8 C3 46 FD FF call $40A742 ( + ) 43607F E8 F6 3A FD FF call $409B7A ( @ ) 436084 E8 23 38 FD FF call $4098AC ( DUP ) 436089 48 B8 18 00 00 00 00 00 00 00 mov rax,$18 436093 E8 EC 48 FD FF call $40A984 ( RP@ ) 436098 E8 A5 46 FD FF call $40A742 ( + ) 43609D E8 D8 3A FD FF call $409B7A ( @ ) 4360A2 E8 96 2F FD FF call $40903D ( MOVE ) 4360A7 E8 00 38 FD FF call $4098AC ( DUP ) 4360AC 48 B8 20 00 00 00 00 00 00 00 mov rax,$20 4360B6 E8 C9 48 FD FF call $40A984 ( RP@ ) 4360BB E8 82 46 FD FF call $40A742 ( + ) 4360C0 E8 B5 3A FD FF call $409B7A ( @ ) 4360C5 E8 E2 37 FD FF call $4098AC ( DUP ) 4360CA 48 B8 30 00 00 00 00 00 00 00 mov rax,$30 4360D4 E8 AB 48 FD FF call $40A984 ( RP@ ) 4360D9 E8 64 46 FD FF call $40A742 ( + ) 4360DE E8 97 3A FD FF call $409B7A ( @ ) 4360E3 E8 C4 37 FD FF call $4098AC ( DUP ) 4360E8 48 B8 18 00 00 00 00 00 00 00 mov rax,$18 4360F2 E8 8D 48 FD FF call $40A984 ( RP@ ) 4360F7 E8 46 46 FD FF call $40A742 ( + ) 4360FC E8 79 3A FD FF call $409B7A ( @ ) 436101 E8 3C 46 FD FF call $40A742 ( + ) 436106 E8 A1 37 FD FF call $4098AC ( DUP ) 43610B 48 B8 28 00 00 00 00 00 00 00 mov rax,$28 436115 E8 6A 48 FD FF call $40A984 ( RP@ ) 43611A E8 23 46 FD FF call $40A742 ( + ) 43611F E8 56 3A FD FF call $409B7A ( @ ) 436124 E8 14 2F FD FF call $40903D ( MOVE ) 436129 E8 7E 37 FD FF call $4098AC ( DUP ) 43612E 48 B8 30 00 00 00 00 00 00 00 mov rax,$30 436138 E8 47 48 FD FF call $40A984 ( RP@ ) 43613D E8 00 46 FD FF call $40A742 ( + ) 436142 E8 33 3A FD FF call $409B7A ( @ ) 436147 E8 60 37 FD FF call $4098AC ( DUP ) 43614C 48 B8 38 00 00 00 00 00 00 00 mov rax,$38 436156 E8 29 48 FD FF call $40A984 ( RP@ ) 43615B E8 E2 45 FD FF call $40A742 ( + ) 436160 E8 15 3A FD FF call $409B7A ( @ ) 436165 C3 ret END-CODE ( 526 bytes, 89 instructions ) 123 abc CODE s+ 436190 48 8B 4D 08 mov rcx,$08[rbp] 436194 48 89 45 F8 mov -$08[rbp],rax 436198 48 89 4D F0 mov -$10[rbp],rcx 43619C 48 8D 6D F0 lea rbp,-$10[rbp] 4361A0 E8 9D 45 FD FF call $40A742 ( + ) 4361A5 E8 37 5B FD FF call $40BCE1 ( ALLOCATE ) 4361AA E8 0F E6 FC FF call $4047BE ( THROW ) 4361AF 48 8B 5D 18 mov rbx,$18[rbp] 4361B3 48 89 45 F8 mov -$08[rbp],rax 4361B7 48 89 45 E8 mov -$18[rbp],rax 4361BB 48 8B 45 10 mov rax,$10[rbp] 4361BF 48 89 5D F0 mov -$10[rbp],rbx 4361C3 48 8D 6D E8 lea rbp,-$18[rbp] 4361C7 E8 71 2E FD FF call $40903D ( MOVE ) 4361CC 48 8B 55 08 mov rdx,$08[rbp] 4361D0 48 8B 75 00 mov rsi,$00[rbp] 4361D4 48 89 45 18 mov $18[rbp],rax 4361D8 48 89 45 F0 mov -$10[rbp],rax 4361DC 48 8B 45 10 mov rax,$10[rbp] 4361E0 48 89 75 08 mov $08[rbp],rsi 4361E4 48 89 55 00 mov $00[rbp],rdx 4361E8 48 89 75 F8 mov -$08[rbp],rsi 4361EC 48 8D 6D F0 lea rbp,-$10[rbp] 4361F0 E8 4D 45 FD FF call $40A742 ( + ) 4361F5 48 8B 5D 00 mov rbx,$00[rbp] 4361F9 48 89 45 00 mov $00[rbp],rax 4361FD 48 8B C3 mov rax,rbx 436200 E8 38 2E FD FF call $40903D ( MOVE ) 436205 E8 38 45 FD FF call $40A742 ( + ) 43620A C3 ret END-CODE ( 123 bytes, 30 instructions ) 123 abc PS. Оптимизация происходит как по объему кода так и по времени выполнения. Здесь используются две формы записи: Основная, например 5|5243452 ( 1 2 3 4 5 --> 5 2 4 3 4 5 2 ) Сокращенная 4$24 ( соответствует 4|123424 в основной форме ) |
Автор: | chess [ Пн май 30, 2022 10:04 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Ввел для Win64FasmForth концепцию NOTFOUND - использование информации заложенной в самом имени слов для формирования кода слов. Попробовал ввести локальное именование слов с использованием NOTFOUND, получилось. Попутно ввел макросы и локально-именованные макросы. Код: REQUIRE { ~mak\locals.f \ locals \ сокращения : I: : IMMEDIATE ; I: ` [COMPILE] POSTPONE ; : d. DUP . ; : h. HEX d. DECIMAL ; : .s CR .S S0 @ SP! ; : nfd ( a u -- ) ?SLITERAL ; : interpret_ \ -> \ меняем интерпретатор под nfd BEGIN PARSE-NAME DUP WHILE SFIND ?DUP IF STATE @ = IF COMPILE, ELSE EXECUTE THEN ELSE S" nfd" SFIND IF EXECUTE ELSE 2DROP ?SLITERAL THEN THEN ?STACK REPEAT 2DROP ; ' interpret_ &INTERPRET ! 0 WARNING ! : nfd { a u } \ пребразователь символов 'c' 'cc' в число a C@ [CHAR] ' = a u + 1- C@ [CHAR] ' = AND u 3 = u 4 = OR AND 0= IF a u nfd EXIT THEN u 3 = IF a 1+ C@ ELSE a 2+ C@ 8 LSHIFT a 1+ C@ OR THEN STATE @ IF LIT, THEN ; \ макросы : LOAD-LEX ( A U -- ) DP @ SWAP DUP ALLOT MOVE 0 C, ; : load-str ( -- a u ) 5 ALLOT DP @ >R BEGIN NextWord ( -- a u ) 2DUP 1 = \ a u a f IF C@ DUP ';' = SWAP DUP '"' = SWAP ']' = OR OR \ a u f IF 2DROP 1 ELSE OVER C@ '\' = IF DROP 0xD PARSE DROP OVER - ERASE \ a a1 a ELSE LOAD-LEX THEN 0 THEN ELSE DROP DUP 0= IF 2DROP REFILL DROP ELSE LOAD-LEX THEN 0 THEN UNTIL DP @ R@ 5 - DP ! 0xE9 C, DUP R@ - W, DUP DP ! R@ SWAP R> - 1- ; : LOAD-STR ( a u -- ) load-str DLIT, ; \ Макросы многострочные - допускают комментарии вида \ ..... : M: ( name "text ;" ) : IMMEDIATE LOAD-STR ` EVALUATE POSTPONE ; ; \ локально-именованные: слова, макросы, переменные, массивы ( упрощенная концепция МОДУЛЕЙ ) CREATE LCODE 0xC000 ALLOT LCODE VALUE DPL \ область памяти для кода слов с локальными именами CREATE LDATA 0xC000 ALLOT LDATA VALUE LDHERE \ область памяти для локально-именованных переменных и массивов 0 VALUE XHERE VARIABLE XDPL \ переменные сохранения указателей компиляции \ область памяти для локальных имен и их адресов 0x800 CONSTANT LENLVOC \ длина словаря CREATE ALVOC LENLVOC ALLOT BL ALVOC C! 1 VALUE LHERE : LVOC ( -- A LEN ) ALVOC LENLVOC ; LVOC BL FILL \ формирование локального имени ( после последнего символа имени идет символ пробела ) : lname, \ a u -- axt TUCK LHERE SWAP MOVE \ лексему в LVOC LHERE + DUP BL SWAP C! \ после лексемы записали BL 1+ DUP TO LHERE \ установить указатель в LVOC после байта BL после лексемы - туда запишем XT кода для лексемы-имени ; : L{ DPL XDPL ! HERE TO XHERE DPL DP ! ; \ переключение на компиляцию в область LCODE : }L DPL HERE XDPL @ - + TO DPL XHERE DP ! ; \ переключение на компиляцию в область CODE : init-lvoc LVOC BL FILL LVOC DROP 1+ TO LHERE ; \ стирание локального словаря в части локальных имен, код лок. слов не удаляется : headl ( a u -- ) lname, DPL SWAP ! LHERE 5 + TO LHERE ; M: nf1-exit { a u s } \ -- a u a u + 1- C@ s <> IF a u nfd EXIT THEN a u ; VARIABLE iol 0 iol ! \ направление ввода-вывода в locname-переменные типа value \ начало формирования кода с локальным именем : nfd ( a u -- ) '(' nf1-exit 1- headl L{ ; \ окончание формирования кода с локальным именем I: ) RET, }L ; \ локально-именованные строки : nfd ( a u -- ) '"' nf1-exit 1- headl L{ LOAD-STR RET, }L ; \ name" текст строки " \ локально-именованные макросы : nfd ( a u -- ) '[' nf1-exit 1- headl L{ LOAD-STR ` EVALUATE RET, }L ; \ name[ текст макроса ] \ склеивание определений - локальный словарь не удаляется, слово определенное по +: добавляется в основной словарь : +: : ; : : init-lvoc : ; \ процедура поиска имени в лок. словаре : lsearch { a u a1 u1 \ a2 } BL a1 u1 + C! a u a1 u1 1+ SEARCH >R DROP TO a2 R> IF a2 u1 TRUE ELSE a u FALSE THEN ; I: is 1 iol ! ; \ устанавливает режим записи, после исполнения записи устанавливает режим чтения \ компиляция слов с локальными именами \ с блокировкой компиляции слов вида Name1...Name9 при совпадению \ лексем вида '1' ... '9'( числа ) из входного потока c последним символом слов NameN : nfd { a u } a C@ '1' '9' 1+ WITHIN u 1 = AND IF a u nfd EXIT THEN LVOC a u lsearch ( a u f ) 0= IF 2DROP a u nfd EXIT THEN + 1+ @ iol @ IF 19 + 0 iol ! THEN COMPILE, ; \ локально-именованные переменые : nfd ( a u -- ) \ типа value '!' nf1-exit 1- headl LDHERE LIT, ` ! L{ LDHERE LIT, ` @ RET, LDHERE LIT, ` ! RET, LDHERE 1 CELLS + TO LDHERE }L ; \ локально-именованные статические массивы : nfd ( a u -- ) \ размер задается числовым литералом [ 20 ] arr] ']' nf1-exit 1- headl L{ LDHERE LIT, RET, LDHERE + TO LDHERE }L ; \ исполнить слово или комбинатор независимо от STATE и от флага IMMEDIATE : nfd { a u } a u + 1- C@ '`' = u 1 > AND 0= IF a u nfd EXIT THEN LVOC a u 1- lsearch \ для локальных слов, определенных с использованием IMMEDIATE слов IF + 1+ @ EXECUTE ELSE a u 1- TYPE SPACE ." not found " CR THEN ; Примеры: Код: : S+ \ a1 u1 a2 u2 u2! a2! u1! a1! u1 u2 + DUP u! ALLOCATE THROW a! a1 a u1 MOVE a2 a u1 + u2 MOVE a u ; SEE S+ S" 123" S" abcd" S+ CR TYPE : type-str str" 123456789ABCDEF " aDO[ OVER + SWAP DO ] str aDO` I C@ . LOOP ; SEE type-str CR type-str Код: CODE S+ 439528 E8 7F 03 FD FF call $4098AC ( DUP ) 43952D 48 B8 B5 B9 42 00 00 00 00 00 mov rax,$42B9B5 439537 E8 1E 07 FD FF call $409C5A ( ! ) 43953C E8 6B 03 FD FF call $4098AC ( DUP ) 439541 48 B8 BD B9 42 00 00 00 00 00 mov rax,$42B9BD 43954B E8 0A 07 FD FF call $409C5A ( ! ) 439550 E8 57 03 FD FF call $4098AC ( DUP ) 439555 48 B8 C5 B9 42 00 00 00 00 00 mov rax,$42B9C5 43955F E8 F6 06 FD FF call $409C5A ( ! ) 439564 E8 43 03 FD FF call $4098AC ( DUP ) 439569 48 B8 CD B9 42 00 00 00 00 00 mov rax,$42B9CD 439573 E8 E2 06 FD FF call $409C5A ( ! ) 439578 E8 1C 64 FE FF call $41F999 ( LCODE+59 ) 43957D E8 C3 63 FE FF call $41F945 ( LCODE+5 ) 439582 E8 BB 11 FD FF call $40A742 ( + ) 439587 E8 20 03 FD FF call $4098AC ( DUP ) 43958C E8 1B 03 FD FF call $4098AC ( DUP ) 439591 48 B8 D5 B9 42 00 00 00 00 00 mov rax,$42B9D5 43959B E8 BA 06 FD FF call $409C5A ( ! ) 4395A0 E8 3C 27 FD FF call $40BCE1 ( ALLOCATE ) 4395A5 E8 14 B2 FC FF call $4047BE ( THROW ) 4395AA E8 FD 02 FD FF call $4098AC ( DUP ) 4395AF 48 B8 DD B9 42 00 00 00 00 00 mov rax,$42B9DD 4395B9 E8 9C 06 FD FF call $409C5A ( ! ) 4395BE E8 00 64 FE FF call $41F9C3 ( LCODE+83 ) 4395C3 E8 4F 64 FE FF call $41FA17 ( LCODE+D7 ) 4395C8 E8 CC 63 FE FF call $41F999 ( LCODE+59 ) 4395CD E8 6B FA FC FF call $40903D ( MOVE ) 4395D2 E8 98 63 FE FF call $41F96F ( LCODE+2F ) 4395D7 E8 3B 64 FE FF call $41FA17 ( LCODE+D7 ) 4395DC E8 B8 63 FE FF call $41F999 ( LCODE+59 ) 4395E1 E8 5C 11 FD FF call $40A742 ( + ) 4395E6 E8 5A 63 FE FF call $41F945 ( LCODE+5 ) 4395EB E8 4D FA FC FF call $40903D ( MOVE ) 4395F0 E8 22 64 FE FF call $41FA17 ( LCODE+D7 ) 4395F5 E8 F3 63 FE FF call $41F9ED ( LCODE+AD ) 4395FA C3 ret END-CODE ( 211 bytes, 37 instructions ) 123abcd CODE type-str 439628 E8 14 64 FE FF call $41FA41 ( LCODE+101 ) 43962D E8 23 03 FD FF call $409955 ( OVER ) 439632 E8 0B 11 FD FF call $40A742 ( + ) 439637 E8 E9 02 FD FF call $409925 ( SWAP ) 43963C E8 D3 16 FD FF call $40AD14 ( XDO ) 439641 68 61 96 43 00 push $439661 439646 52 push edx 439647 53 push ebx 439648 E8 05 16 FD FF call $40AC52 ( I ) 43964D E8 69 05 FD FF call $409BBB ( C@ ) 439652 E8 93 A9 FC FF call $403FEA ( . ) 439657 FF 04 24 inc dword PTR [esp] 43965A 71 EC jNo $439648 43965C 48 8D 64 24 18 lea rsp,$18[rsp] 439661 C3 ret END-CODE ( 58 bytes, 15 instructions ) 49 50 51 52 53 54 55 56 57 65 66 67 68 69 70 Внутренности locname слова str Код: $41FA41 see
CODE call 41FA41 41FA41 E9 10 00 00 00 jmp $41FA56 ( LCODE+116 ) 41FA46 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 00 123456789ABCDEF. 41FA56 E8 51 9E FE FF call $4098AC ( DUP ) 41FA5B 48 B8 46 FA 41 00 00 00 00 00 mov rax,$41FA46 41FA65 E8 42 9E FE FF call $4098AC ( DUP ) 41FA6A 48 B8 0F 00 00 00 00 00 00 00 mov rax,$F 41FA74 C3 ret END-CODE ( 52 bytes, 6 instructions ) |
Автор: | chess [ Вс июн 05, 2022 23:33 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Реализовал измеритель времени однократного исполнения отдельных слов для WinFAsmForth64, сначала пишем на fasm в ядро форт-системы: Код: cfa_AHEADER 0,'xmeter',xmeter movd xmm0, eax xor eax, eax cpuid rdtsc movd xmm1, eax movd ebx, xmm0 call rbx xor eax, eax cpuid rdtsc movd ecx, xmm1 sub eax, ecx movd xmm2, eax xor eax, eax cpuid rdtsc movd xmm1, eax movd ebx, xmm0 xor eax, eax cpuid rdtsc movd ecx, xmm1 sub eax, ecx mov ebx, eax movd eax, xmm2 sub eax, ebx ret потом дописываем в уже сформированной форт-системе: Код: : dT ( "name" -- ) ' xmeter CR NIP . ." ticks " CR S0 @ SP! ; использование: Код: dT DROP результат: Код: 81 ticks
|
Автор: | chess [ Ср дек 14, 2022 00:59 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Изменяю синтаксис манипуляторов с целью упрощения их использования для ускорения создания программ и оптимизации их кода. Код: \ сумма попарных произведений для четырех чисел : dcr4 { a b c d } \ spf b c + d + a * c d + b * + c d * + ; SEE dcr4 SEE DRMOVE m{ : dc4 | a b c d | \ spf + манипуляторы b c + d + a * c d + b * + c d * + T> a ; }m SEE dc4 лог. Код: CODE dcr4 627B53 8945FC MOV FC [EBP] , EAX 627B56 B810000000 MOV EAX , # 10 627B5B 8D6DFC LEA EBP , FC [EBP] 627B5E E881B5F2FF CALL 5530E4 ( DRMOVE ) 627B63 6810000000 PUSH , # 10 627B68 6868325500 PUSH , # 553268 627B6D 8945FC MOV FC [EBP] , EAX 627B70 8B442410 MOV EAX , 10 [ESP] 627B74 0344240C ADD EAX , C [ESP] 627B78 03442408 ADD EAX , 8 [ESP] 627B7C 8945F8 MOV F8 [EBP] , EAX 627B7F 8B442414 MOV EAX , 14 [ESP] 627B83 F76DF8 IMUL F8 [EBP] 627B86 8945F8 MOV F8 [EBP] , EAX 627B89 8B44240C MOV EAX , C [ESP] 627B8D 03442408 ADD EAX , 8 [ESP] 627B91 8945F4 MOV F4 [EBP] , EAX 627B94 8B442410 MOV EAX , 10 [ESP] 627B98 F76DF4 IMUL F4 [EBP] 627B9B 0345F8 ADD EAX , F8 [EBP] 627B9E 8945F8 MOV F8 [EBP] , EAX 627BA1 8B44240C MOV EAX , C [ESP] 627BA5 8945F4 MOV F4 [EBP] , EAX 627BA8 8B442408 MOV EAX , 8 [ESP] 627BAC F76DF4 IMUL F4 [EBP] 627BAF 0345F8 ADD EAX , F8 [EBP] 627BB2 8D6DFC LEA EBP , FC [EBP] 627BB5 C3 RET NEAR END-CODE ( 99 bytes, 28 instructions ) CODE DRMOVE 5530E4 5A POP EDX 5530E5 8BF0 MOV ESI , EAX 5530E7 FF7435FC PUSH FC [EBP] [ESI] 5530EB 83EE04 SUB ESI , # 4 5530EE 75F7 JNE 5530E7 5530F0 03E8 ADD EBP , EAX 5530F2 8B4500 MOV EAX , 0 [EBP] 5530F5 8D6D04 LEA EBP , 4 [EBP] 5530F8 FFE2 JMP EDX END-CODE ( 22 bytes, 9 instructions ) CODE dc4 627BC7 8945FC MOV FC [EBP] , EAX 627BCA 8B4504 MOV EAX , 4 [EBP] 627BCD 034500 ADD EAX , 0 [EBP] 627BD0 0345FC ADD EAX , FC [EBP] 627BD3 F76D08 IMUL 8 [EBP] 627BD6 8945F8 MOV F8 [EBP] , EAX 627BD9 8B4500 MOV EAX , 0 [EBP] 627BDC 0345FC ADD EAX , FC [EBP] 627BDF F76D04 IMUL 4 [EBP] 627BE2 0345F8 ADD EAX , F8 [EBP] 627BE5 8945F8 MOV F8 [EBP] , EAX 627BE8 8B5D00 MOV EBX , 0 [EBP] 627BEB 0FAF5DFC IMUL EBX , FC [EBP] 627BEF 8BC3 MOV EAX , EBX 627BF1 0345F8 ADD EAX , F8 [EBP] 627BF4 8D6D0C LEA EBP , C [EBP] 627BF7 C3 RET NEAR END-CODE ( 49 bytes, 17 instructions ) Код на лок. переменных 37 инструкций Код на манипуляторах 17 инструкций На обычном форте это (и многое другое) писать гораздо дольше Фрагмент типа ( T> a ) можно написать например так | res | Out: res Код: : dc4 | a b c d | b c + d + a * c d + b * + c d * + | res | out: res ; Где out: автоматически расположит указанное количество выходных параметров в указанном порядке на стеке. |
Автор: | chess [ Вс дек 18, 2022 23:24 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Для формирования предельно оптимального по скорости форт-кода сделал 'стековый' ассемблер( плюс три строчки в текст транспилятора ) Код: m{ \ Сумма квадратов трех чисел : SumSq | n1 n2 n3 | A{ ebx n1 mov ecx n2 mov eax eax imul ebx ebx imul ecx ecx imul eax ebx add eax ecx add }A T> n1 ; }m SEE SumSq 1 2 3 SumSq .s лог Код: CODE SumSq 628AC7 8B5D04 MOV EBX , 4 [EBP] 628ACA 8B4D00 MOV ECX , 0 [EBP] 628ACD F7E8 IMUL EAX 628ACF 0FAFDB IMUL EBX , EBX 628AD2 0FAFC9 IMUL ECX , ECX 628AD5 03C3 ADD EAX , EBX 628AD7 03C1 ADD EAX , ECX 628AD9 8D6D08 LEA EBP , 8 [EBP] 628ADC C3 RET NEAR END-CODE ( 22 bytes, 9 instructions ) 14 T.е. можно делать ассемблерные вставки, но конечно проще такие вставки делать прямо в манипуляторной форме: /[3{b1:c2:aa*bb*cc*ab+ac+}'1. Короче и обзорность лучше. |
Автор: | chess [ Ср дек 28, 2022 21:31 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Сравнил манипуляторы, задаваемые в форме определений с локальными переменными с форт-определениями (при включенном оптимизаторе) в части скорости кода. Иногда форт проигрывает: Код: \ форт : MAXMIN1 >R MAX R> MIN ; SEE MAXMIN1 : MAXMIN2 -ROT MAX MIN ; SEE MAXMIN2 SEE MAX SEE MIN \ манипуляторы m: MAXMINm | a b c | a b MAX c MIN ;m SEE MAXMINm лог Код: CODE MAXMIN1 629287 50 PUSH EAX 629288 8B4500 MOV EAX , 0 [EBP] 62928B 8D6D04 LEA EBP , 4 [EBP] 62928E E8DD90F2FF CALL 552370 ( MAX ) 629293 8945FC MOV FC [EBP] , EAX 629296 58 POP EAX 629297 8D6DFC LEA EBP , FC [EBP] 62929A E8ED90F2FF CALL 55238C ( MIN ) 62929F C3 RET NEAR END-CODE ( 25 bytes, 9 instructions ) CODE MAXMIN2 6292B7 8B5504 MOV EDX , 4 [EBP] 6292BA 894504 MOV 4 [EBP] , EAX 6292BD 8B4500 MOV EAX , 0 [EBP] 6292C0 895500 MOV 0 [EBP] , EDX 6292C3 E8A890F2FF CALL 552370 ( MAX ) 6292C8 E8BF90F2FF CALL 55238C ( MIN ) 6292CD C3 RET NEAR END-CODE ( 23 bytes, 7 instructions ) CODE MAX 552370 8B5500 MOV EDX , 0 [EBP] 552373 3BD0 CMP EDX , EAX 552375 0F4FC2 CMOVG EAX , EDX 552378 8D6D04 LEA EBP , 4 [EBP] 55237B C3 RET NEAR END-CODE ( 12 bytes, 5 instructions ) CODE MIN 55238C 8B5500 MOV EDX , 0 [EBP] 55238F 3BD0 CMP EDX , EAX 552391 0F4CC2 CMOVL EAX , EDX 552394 8D6D04 LEA EBP , 4 [EBP] 552397 C3 RET NEAR END-CODE ( 12 bytes, 5 instructions ) CODE MAXMINm 6292E3 8945FC MOV FC [EBP] , EAX 6292E6 8B4500 MOV EAX , 0 [EBP] 6292E9 8B5504 MOV EDX , 4 [EBP] 6292EC 3BD0 CMP EDX , EAX 6292EE 0F4FC2 CMOVG EAX , EDX 6292F1 8B55FC MOV EDX , FC [EBP] 6292F4 3BD0 CMP EDX , EAX 6292F6 0F4CC2 CMOVL EAX , EDX 6292F9 8D6D08 LEA EBP , 8 [EBP] 6292FC C3 RET NEAR END-CODE ( 26 bytes, 10 instructions ) В вариантах на форте 19 и 17 инструкций, а на манипуляторах 10. Как правило манипуляторы дают сравнимое с фортом+оптимизатор быстродействие семантически эквивалентных определений, но позволяют писать эти определения так же быстро как и с помощью локальных переменных. |
Автор: | chess [ Сб дек 31, 2022 00:46 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
В виртуальной машине форта на манипуляторах трактовка стека параметров расширена, а именно, стек рассматривается как массив и как стек одновременно. Поэтому число команд виртуальной машины также расширено операциями между ячейками стека. В этом случае возможна 'ручная' оптимизация кода без выхода на ассемблер. Код: \ обычный вариант определения площади треугольника m: s3 | a b c | a b + c + 2x / | p | p p a - * p b - * p c - * sqrt ;m SEE s3 3 4 5 s3 .s \ оптимизированный вариант с использованием операций между ячейками m: s3c | a b c | c | p | p b c+ p a c+ p 2x c/ a p c- b p c- c p c- p a c* p b c* p c c* NEGATE sqrt ;m SEE s3c 3 4 5 s3c .s \ обычный вариант суммы квадратов трех чисел m: ssq3 | a b c | a a * b b * + c c * + ;m SEE ssq3 1 2 3 ssq3 . \ оптимизированный вариант с использованием операций между ячейками m: ssq3c | a b c | a a c* b b c* c c c* c b c+ c a c+ ;m SEE ssq3c 1 2 3 ssq3c . лог Код: CODE s3 6293DF 8945FC MOV FC [EBP] , EAX 6293E2 8B4504 MOV EAX , 4 [EBP] 6293E5 034500 ADD EAX , 0 [EBP] 6293E8 0345FC ADD EAX , FC [EBP] 6293EB 8945F8 MOV F8 [EBP] , EAX 6293EE B802000000 MOV EAX , # 2 6293F3 8BC8 MOV ECX , EAX 6293F5 8B45F8 MOV EAX , F8 [EBP] 6293F8 99 CDQ 6293F9 F7F9 IDIV ECX 6293FB 8945F8 MOV F8 [EBP] , EAX 6293FE 8945F4 MOV F4 [EBP] , EAX 629401 8B45F8 MOV EAX , F8 [EBP] 629404 2B4504 SUB EAX , 4 [EBP] 629407 F76DF4 IMUL F4 [EBP] 62940A 8945F4 MOV F4 [EBP] , EAX 62940D 8B45F8 MOV EAX , F8 [EBP] 629410 2B4500 SUB EAX , 0 [EBP] 629413 F76DF4 IMUL F4 [EBP] 629416 8945F4 MOV F4 [EBP] , EAX 629419 8B45F8 MOV EAX , F8 [EBP] 62941C 2B45FC SUB EAX , FC [EBP] 62941F F76DF4 IMUL F4 [EBP] 629422 8D6DF8 LEA EBP , F8 [EBP] 629425 E89DDBFEFF CALL 616FC7 ( sqrt ) 62942A 8D6D10 LEA EBP , 10 [EBP] 62942D C3 RET NEAR END-CODE ( 79 bytes, 27 instructions ) 6 CODE s3c 62943F 8945FC MOV FC [EBP] , EAX 629442 034500 ADD EAX , 0 [EBP] 629445 034504 ADD EAX , 4 [EBP] 629448 C7C102000000 MOV ECX , # 2 62944E 99 CDQ 62944F F7F9 IDIV ECX 629451 294504 SUB 4 [EBP] , EAX 629454 294500 SUB 0 [EBP] , EAX 629457 2945FC SUB FC [EBP] , EAX 62945A 0FAF4504 IMUL EAX , 4 [EBP] 62945E 0FAF4500 IMUL EAX , 0 [EBP] 629462 0FAF45FC IMUL EAX , FC [EBP] 629466 F7D8 NEG EAX 629468 8D6DFC LEA EBP , FC [EBP] 62946B E857DBFEFF CALL 616FC7 ( sqrt ) 629470 8D6D0C LEA EBP , C [EBP] 629473 C3 RET NEAR END-CODE ( 53 bytes, 17 instructions ) 6 лог CODE ssq3 629487 8945FC MOV FC [EBP] , EAX 62948A 8B5D04 MOV EBX , 4 [EBP] 62948D 0FAF5D04 IMUL EBX , 4 [EBP] 629491 8BC3 MOV EAX , EBX 629493 8945F8 MOV F8 [EBP] , EAX 629496 8B5D00 MOV EBX , 0 [EBP] 629499 0FAF5D00 IMUL EBX , 0 [EBP] 62949D 8BC3 MOV EAX , EBX 62949F 0345F8 ADD EAX , F8 [EBP] 6294A2 8945F8 MOV F8 [EBP] , EAX 6294A5 8B5DFC MOV EBX , FC [EBP] 6294A8 0FAF5DFC IMUL EBX , FC [EBP] 6294AC 8BC3 MOV EAX , EBX 6294AE 0345F8 ADD EAX , F8 [EBP] 6294B1 8D6D08 LEA EBP , 8 [EBP] 6294B4 C3 RET NEAR END-CODE ( 46 bytes, 16 instructions ) 14 CODE ssq3c 6294C7 8B5D04 MOV EBX , 4 [EBP] 6294CA 0FAF5D04 IMUL EBX , 4 [EBP] 6294CE 895D04 MOV 4 [EBP] , EBX 6294D1 8B5D00 MOV EBX , 0 [EBP] 6294D4 0FAF5D00 IMUL EBX , 0 [EBP] 6294D8 895D00 MOV 0 [EBP] , EBX 6294DB F7E8 IMUL EAX 6294DD 034500 ADD EAX , 0 [EBP] 6294E0 034504 ADD EAX , 4 [EBP] 6294E3 8D6D08 LEA EBP , 8 [EBP] 6294E6 C3 RET NEAR END-CODE ( 32 bytes, 11 instructions ) 14 Число инструкций на треть где-то уменьшилось. Реализация такой оптимизазации тривиальна. ps. Эксперименты с фортом на манипуляторах подводят к полному пересмотру концепции стекового языка как в части экономии времени при создании надежных программ, так и в части повышения эффективности кода программ. |
Автор: | KPG [ Сб дек 31, 2022 16:46 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
chess писал(а): Число инструкций на треть где-то уменьшилось. Реализация такой оптимизазации тривиальна. ps. Эксперименты с фортом на манипуляторах подводят к полному пересмотру концепции стекового языка как в части экономии времени при создании надежных программ, так и в части повышения эффективности кода программ. Может имеет смысл оформить полученные результаты в виде статьи и разместить её, к примеру, на площадке типа Хабр? |
Автор: | Alex [ Пн янв 02, 2023 22:21 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
предлагалось расширить виртуальную машину форт регистрами A,B,X и Y https://www.complang.tuwien.ac.at/anton/euroforth/ef08/papers/pelc.pdf интересно проверить Вашу гипотезу иной реализацией , например с другим процессором (ARM) или где идет компиляция в WebAssembly или другой язык. |
Автор: | Hishnik [ Пн янв 02, 2023 22:40 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Ну и как, с 2008 года оно получило широкое распространение? Цитата: The canonical Forth virtual machine is weak in several areas. 1) It does not execute C well, which is important for commercial exploitation of silicon stack machines. 2) It is weak for DSP operations, which restricts performance in embedded applications without changes to the VM or much increased compiler complexity, 3) Without index operations, it is cumbersome to deal with complex data structures whose base address is passed as an argument to a word. 1) А что вообще можно сказать про Си в отрыве от промежуточного представления, в которое компилируется исходный текст? Стековая машина - вполне рабочее промежуточное представление, естественно, с присущими недостатками. 2) DSP вообще не для процессоров, это для аппаратных ускорителей. По крайней мере, для специализированных расширений. Оптимизировать такты на DSP - изначально провальное занятие, там должен быть один такт на отвод фильтра, со всеми сопутствующими операциями, производимыми параллельно. 3) А потом будет передаваться три аргумента. А потом четыре. Почему тогда так мало регистров? Давайте уже блок на 32 РОН и 8 индексных, м? |
Автор: | Victor__v [ Чт янв 05, 2023 17:58 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Цитата: ELSE S" nfd" SFIND IF EXECUTE ELSE 2DROP ?SLITERAL THEN Переопределяемое слово (VECT)? Функция по перебору массива с обработчиками? Не, давайте тянуть потенциально бажное решение из SPF |
Автор: | F-MAP [ Пт янв 06, 2023 20:17 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
Victor__v писал(а): Цитата: ELSE S" nfd" SFIND IF EXECUTE ELSE 2DROP ?SLITERAL THEN Переопределяемое слово (VECT)? Функция по перебору массива с обработчиками? Не, давайте тянуть потенциально бажное решение из SPF Что так хаять spf, предложи свое решение, чем махать лаптями.. |
Автор: | Victor__v [ Сб янв 07, 2023 11:46 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
F-MAP писал(а): Victor__v писал(а): Цитата: ELSE S" nfd" SFIND IF EXECUTE ELSE 2DROP ?SLITERAL THEN Переопределяемое слово (VECT)? Функция по перебору массива с обработчиками? Не, давайте тянуть потенциально бажное решение из SPF Что так хаять spf, предложи свое решение, чем махать лаптями.. О, аргументация "сперва добейся") Очаровательно. То что я машу лаптями, как-то меняет тот факт, что реализация расширения NOTFOUND в СПФ потенциально багоопасная и тормознутая при этом? И свое предложение у меня есть. В своем форте реализовано и работает. viewtopic.php?f=58&t=3273 |
Автор: | Hishnik [ Сб янв 07, 2023 16:25 ] |
Заголовок сообщения: | Re: Еще один способ работы с параметрами на стеке |
А spf еще жив? Архитектурно он не пережил даже перехода DOS -> Windows. Все вот эти "стандарт де-факто" и "надо либы какие-нибудь продвигать" - уже трепыхания рыбы, которая неплохо плавала, но попыталась вылезти на сушу и плавать там, помахивая плавниками "де-факто". |
Страница 4 из 5 | Часовой пояс: UTC + 3 часа [ Летнее время ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |