Москвич-408 — элегантность, ставшая классикой

Тема в разделе "Vulkan", создана пользователем ml64, 25 июл 2026.

  1. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    194
    Да... Команда нужная!
    т.е. поменять Mov Al, 'v' на Mov Al, 10 (после конца предыдущей - начало следующей).

    Непонятно почему, несмотря на
    Вы приводите массивные примеры "Case"- программирования "If"-ами?
    Вместо:
    Код (ASM):
    1.   Mov  eSi, Что разобрать
    2.   Mov  eCx, Сколько максимально -
    3. ; Т.Е. длина файла eCx и ([eSi+eCx]=0=EoF) должен находиться
    4. ; "вне" файла и рассмотрение его избыточно !
    5.   ClD  ; / StD - направление
    6.   xOr  eAx, eAx
    7.   LEA  eBx, [BitMap1]
    8.   LEA  eDx, [CallTab1]  ; или [JmpTab1]
    9. _1:
    10.   LodsB  ; например
    11.   BT  [eBx], eAx  ;;
    12.   JnC  _2  ; возможно ускоряет, если мало токенов в обработке
    13.   Call  [eDx + eAx * 4]  ; если надо почитабельнее
    14. ;  Jmp  [eDx + eAx * 4]  ; как в вашем случае с "возвратом" Jmp _2
    15. _2:
    16.   LoopNZd _1
    естественно при работе внутри цикла (_1:) eBx, eDx и даже
    eSi c eCx могут меняться для следующих этапов "дерева" разбора!
    Простой пример:
    попался комментарий '#'
    Код (ASM):
    1. _NextLine Proc  ; для  Call  [eDx + eAx * 4]
    2.   Mov  eDi, eSi
    3.   Mov  Al, 10 ; конец строки
    4.   RepNE  ScasB
    5.   Mov  eSi, eDi
    6.   Test  eCx, eCx
    7.   Ret
    8. _NextLine EndP
    Возникает простой вопрос - может ли быть более 1-го токена в строке? Если не может, то после него... до конца строки включительно рассматривать нечего, в вами приведенном коде, и т.д. и т.п.
    Я пока не планирую процессор мощнее (E8400 у меня), но интересно, ~во сколько VPCMPISTRI быстрее ее аналога выше?
    P.S. От ошибок никто не застрахован.(((
    Либо 13,10, либо 0Dh, 0Ah.
     
    Последнее редактирование модератором: 17 авг 2026 в 07:30
  2. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    194
    Сначала по другому было:
    Код (ASM):
    1.   Mov  eSi, Что разобрать
    2.   Mov  eCx, Сколько максимально -
    3. ; Т.Е. длина файла eCx и ([eSi+eCx]=0=EoF) должен находиться
    4. ; "вне" файла и рассмотрение его избыточно !
    5.   ClD  ; / StD - направление
    6.   xOr  eAx, eAx
    7.   LEA  eDx, [CallTab1]  ; или [JmpTab1]
    8. _1:
    9.   LodsB  ; например
    10.   Call  [eDx + eAx * 4]  ; если надо почитабельнее
    11. ;  Jmp  [eDx + eAx * 4]  ; как в вашем случае с "возвратом" на _2
    12. ; в JmpTab1  dd  _2 ; для необрабатывемых
    13.  _2:
    14.   LoopD _1
    15.  
    16. _NextLine Proc  ; для  Call  [eDx + eAx * 4]
    17.   Mov  eDi, eSi
    18.   Mov  Al, 10 ; конец строки
    19.   RepNE  ScasB
    20.   Mov  eSi, eDi
    21.   Cmp  eCx, 1  ;;
    22.   AdC  eCx, 0  ; так надежнее при возврате на _2:
    23.   Ret
    24. _NextLine EndP
    потом подумал улучшить... и в конце - 1-ну инструкцию "пожалел" и ошибся - может неконролируемо вывалиться:
    Код (ASM):
    1. ....
    2.   xOr  eAx, eAx  ; ZF=1 в самом начале по JnC _2
    3. ....
    4.   JnC _2
    5. ....
    6.  _2:
    7.   LoopNZd _1  ; при уходе на
    8. .....
    9. _Ret Proc  ; для  Call  [eDx + eAx * 4]
    10.   Ret
    11. _Ret EndP
    12. ....
    13. ;или  в при  JmpTab1  dd  _2 ; для необрабатывемых
    P.S. У меня сейчас есть задачи обработки строк методом проб и ошибок))) поэтому возможно даже излишне активен в теме.
     
    Последнее редактирование модератором: 17 авг 2026 в 07:27
  3. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    Можно сделать надежно(элитный способ) для подгрузки сторонних проектов(если не известно какое будет форматирование/мусорные токены), но при этом будет больше вычислений, сам код при этом будет гораздо лаконичнее. Либо 2 варианта загрузки(я так обычно не делаю): быстрый(обработка переносов/мусорных токенов - как у вас) и медленный(максимально надежный, но там немного другая логика).
     
  4. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    А в этом и особенность низкоуровневого подхода.
    Когда я пишу на ассемблере, я не думаю о конструкциях Select Case, While или If.
    Это касается и организации главного цикла, и обработчика сообщений, и парсера.

    Когда я обрабатываю сообщения, я просто пробегаю по условиям в порядке их вероятности и/или критичности:
    Код (ASM):
    1. ;Messages Arranged by Probability
    2. cmp edx,111h
    3. je lbl_wmCommand ;Самое ожидаемое
    4. cmp edx,5
    5. je lbl_wmSize ;Приходит несколько раз
    6. cmp edx,10h
    7. je lbl_wmClose ;Один либо несколько раз, если юзер передумает
    8. cmp edx,2
    9. je lbl_wmDestroy ;Ждём единственного случая
    10. cmp edx,1
    11. je lbl_wmCreate ;Один раз в начале, дальше - балласт
    12. ;None of the Above
    13. call DefWindowProcA
    14.  
    Аналогично в парсере:
    Код (ASM):
    1. ;Token detection. Arranged by Probability
    2. ;mov rcx,pCurrentPosition
    3. cmp byte ptr[rcx],76h ;"v" - Вершин будут десятки тысяч
    4. je lbl_TokenStartsWithV
    5. cmp byte ptr[rcx],66h ;"f" - Полигонов будут тысячи
    6. je lbl_TokenFace
    7. cmp byte ptr[rcx],67h ;"g" - Несколько десятков групп
    8. je lbl_TokenGroup
    9. cmp dword ptr[rcx],6D657375h ;"usem" in reverse order - part of "usemtl" - Материалов наберётся с десяток
    10. je lbl_TokenUseMtl
    11. cmp byte ptr[rcx],6Fh ;"o" - Несколько объектов
    12. je lbl_TokenObject
    13. cmp dword ptr[rcx],6C6C746Dh; "mtll" in reverse order - part of "mtllib" - Одна или пара библиотек
    14. je lbl_TokenMtlLib
    15. jmp lbl_SkipByte
    Но: до разбора токенов надо ещё добраться!
    Допустим, я на первом проходе считаю количество токенов, чтобы узнать размер выделяемой памяти.
    Вот типичная строка:
    f -97/-112/-128 -81/-88/-104 -82/-89/-105
    Я увидел токен f и увеличил inc gnTotalFaces. После этого остаток строки мне не нужен.
    Теперь мне нужно искать 13h,10h либо EoF.
    Я не буду гонять через память каждый байт инструкциями lodsb/cmpsb, я лучше загружу сразу 16 байт и проверю их внутри CPU.

    Вопрос по существу.
    Вразумительных отчётов я не видел (хотя и не искал особо), мне сейчас интереснее проверить на своём опыте.
    Очень может быть, что Вы правы, и для перебора строк лучше побайтовые команды.
    Но у меня сейчас такое приложение, в котором мозги уже переключились на векторный подход,
    поэтому хочется выдержать чистоту жанра.
     
  5. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    2026-08-15_23-10-44.png
     
    ml64 нравится это.
  6. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    Код на си.
    2026-08-15_23-59-13.png
     

    Вложения:

    • parser.rar
      Размер файла:
      18,2 КБ
      Просмотров:
      10
    ml64 нравится это.
  7. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    А я пока собрал то, о чём говорил:

    Код (ASM):
    1. countObjEntities proc
    2.  
    3. PROLOG 100h
    4.  
    5. ;Initialize Counters
    6. mov gnTotalObjects,0
    7. mov gnTotalGroups,0
    8. mov gnTotalSubGroups,0
    9. mov gnTotalFaces,0
    10. mov gnTotalVertices,0
    11. mov gnTotalNormals,0
    12. mov gnTotalTextureVectors,0
    13. mov gnTotalMtlLibs,0
    14.  
    15. ;Set the Local Pointer
    16. mov rcx,gpObjDataStart
    17. cmp rcx,gpObjDataEnd
    18. jge lbl_EndOfFile
    19.  
    20.  
    21. lbl_ReadNextLine:
    22. mov rsi,rcx ;pCurrentPosition
    23. ;Do not use rcx to store pCurrentPosition
    24. ;because it is used by vpcmpistri as index
    25.  
    26. lbl_NextXmmword_0:
    27. cmp rsi,gpObjDataEnd
    28. jge lbl_EndOfFile
    29.  
    30. ;Pattern: ASCII code: 'm', '#', 's', 'u', 'o', 'g', 'f', 'v'
    31. mov rax,6D2373756F676676h ;m#suogfv
    32. movq xmm0,rax
    33. ;Compare bytes at [rsi] against pattern in XMM0
    34. ;Mode 0: equal_any, positive polarity, implicit length
    35. vpcmpistri xmm0,xmmword ptr[rsi],0
    36. jz lbl_EndOfFile
    37. jc lbl_TokenFound
    38. add rsi,10h ;Compute the next address to check
    39. jmp lbl_NextXmmword_0
    40. lbl_TokenFound:
    41. ;ECX contains the index of the first found character
    42. add rcx,rsi ;Compute the absolute address
    43. cmp rcx,gpObjDataEnd
    44. jge lbl_EndOfFile
    45.  
    46.  
    47.  
    48.  
    49. ;Token detection. Arranged by Probability
    50. cmp byte ptr[rcx],76h ;"v"
    51. je lbl_BranchV
    52. cmp byte ptr[rcx],66h ;"f"
    53. je lbl_BranchF
    54. cmp byte ptr[rcx],67h ;"g"
    55. je lbl_BranchG
    56. cmp byte ptr[rcx],6Fh ;"o"
    57. je lbl_BranchO
    58. cmp byte ptr[rcx],75h ;"u"
    59. je lbl_BranchU
    60. cmp byte ptr[rcx],73h ;"s"
    61. je lbl_BranchS
    62. cmp byte ptr[rcx],23h ;"#"
    63. je lbl_BranchComment
    64. cmp byte ptr[rcx],6Dh; "m"
    65. je lbl_BranchM
    66. jmp lbl_FindNextLine
    67.  
    68.  
    69.  
    70.  
    71. ;Branch "v"
    72. lbl_BranchV:
    73. inc rcx ;Check what's next to "v"
    74. cmp byte ptr[rcx],20h ;Space after "v" - Most probable
    75. je lbl_TokenVertex
    76. cmp byte ptr[rcx],6Eh ;"n" after "v"
    77. je lbl_TokenVN
    78. cmp byte ptr[rcx],74h ;"t" after "v"
    79. je lbl_TokenVT
    80. cmp byte ptr[rcx],9 ;Tab after "v" - Least probable
    81. je lbl_TokenVertex
    82. jmp lbl_FindNextLine
    83.  
    84. ;Count vertex: v x y z
    85. lbl_TokenVertex:
    86. inc gnTotalVertices
    87. jmp lbl_FindNextLine
    88.  
    89. ;Branch "vn"
    90. lbl_BranchVN:
    91. inc rcx ;Check what's next to "vn" - Most probable
    92. cmp byte ptr[rcx],20h ;Space after "vn"
    93. je lbl_TokenNormal
    94. cmp byte ptr[rcx],9 ;Tab after "vn" - Least probable
    95. je lbl_TokenNormal
    96. jmp lbl_FindNextLine ;Junk
    97.  
    98. ;Count normal: vn x y z
    99. lbl_TokenNormal:
    100. inc gnTotalNormals
    101. jmp lbl_FindNextLine
    102.  
    103. ;Branch "vt"
    104. lbl_BranchVT:
    105. inc rcx ;Check what's next to "vt"
    106. cmp byte ptr[rcx],20h ;Space after "vt" - Most probable
    107. je lbl_TokenTextureVector
    108. cmp byte ptr[rcx],9 ;Tab after "vt" - Least probable
    109. je lbl_TokenTextureVector
    110. jmp lbl_FindNextLine ;Junk
    111.  
    112. ;Count texture vector: vt u v w
    113. lbl_TokenTextureVector:
    114. inc gnTotalTextureVectors
    115. jmp lbl_FindNextLine
    116.  
    117. ;Branch "f"
    118. lbl_BranchF:
    119. inc rcx ;Check what's next to "f"
    120. cmp byte ptr[rcx],20h ;Space after "f" - Most probable
    121. je lbl_TokenFace
    122. cmp byte ptr[rcx],9 ;Tab after "f" - Least probable
    123. je lbl_TokenFace
    124. jmp lbl_FindNextLine ;Junk
    125.  
    126. ;Count face: f v/vt/vn v/vt/vn v/vt/vn
    127. lbl_TokenFace:
    128. inc gnTotalFaces
    129. jmp lbl_FindNextLine
    130.  
    131. ;Branch "g"
    132. lbl_BranchG:
    133. inc rcx ;Check what's next to "g"
    134. cmp byte ptr[rcx],20h ;Space after "g" - Most probable
    135. je lbl_TokenGroup
    136. cmp byte ptr[rcx],9 ;Tab after "g" - Least probable
    137. je lbl_TokenGroup
    138. jmp lbl_FindNextLine ;Junk
    139.  
    140. ;Count object name: g name
    141. lbl_TokenGroup:
    142. inc gnTotalGroups
    143. jmp lbl_FindNextLine
    144.  
    145. ;Branch "o"
    146. lbl_BranchO:
    147. inc rcx ;Check what's next to "o"
    148. cmp byte ptr[rcx],20h ;Space after "o" - Most probable
    149. je lbl_TokenObject
    150. cmp byte ptr[rcx],9 ;Tab after "o" - Least probable
    151. je lbl_TokenObject
    152. jmp lbl_FindNextLine ;Junk
    153.  
    154. ;Count object name: o name
    155. lbl_TokenObject:
    156. inc gnTotalObjects
    157. jmp lbl_FindNextLine
    158.  
    159. ;Branch "U"
    160. lbl_BranchU:
    161. mov rax,qword ptr[rcx] ;"??ltmesu" - "usemtl" and two unknown bytes in reverse order
    162. shl rax,10h ;Zero out two latter bytes
    163. mov rbx,6c746D6573750000h ;"usemtl" and two zeroes in reverse order
    164. test rax,rbx
    165. jnz lbl_FindNextLine ;Junk
    166. add rcx,6 ;Skip Token
    167. cmp byte ptr[rcx],20h ;Space after "mtllib" - Most probable
    168. je lbl_TokenUseMtl
    169. cmp byte ptr[rcx],9 ;Tab after "mtllib" - Least probable
    170. je lbl_TokenUseMtl
    171. jmp lbl_FindNextLine ;Junk
    172.  
    173. ;Count SubGroup: "usemtl"
    174. lbl_TokenUseMtl:
    175. inc gnTotalSubGroups
    176. add rcx,6 ;Skip Token
    177. jmp lbl_FindNextLine
    178.  
    179. ;Branch "s"
    180. lbl_BranchS:
    181. inc rcx ;Check what's next to "s"
    182. ;cmp byte ptr[rcx],20h ;Space after "o" - Most probable
    183. ;je lbl_TokenS
    184. ;cmp byte ptr[rcx],9 ;Tab after "o" - Least probable
    185. ;je lbl_TokenS
    186. jmp lbl_FindNextLine ;Skip temporarily
    187.  
    188. ;Branch "#"
    189. lbl_BranchComment:
    190. inc rcx ;Check what's next to "s"
    191. ;cmp byte ptr[rcx],20h ;Space after "#" - Most probable
    192. ;je lbl_TokenS
    193. ;cmp byte ptr[rcx],9 ;Tab after "#" - Least probable
    194. ;je lbl_TokenS
    195. jmp lbl_FindNextLine ;Skip temporarily
    196.  
    197. ;Branch "m"
    198. lbl_BranchM:
    199. mov rax,qword ptr[rcx] ;"??billtm" - "mtllib" and two unknown bytes in reverse order
    200. shl rax,10h ;Zero out two latter bytes
    201. mov rbx,62696c6c746D0000h ;"mtllib" and two zeroes in reverse order
    202. test rax,rbx
    203. jnz lbl_FindNextLine ;Junk
    204. add rcx,6 ;Skip Token
    205. cmp byte ptr[rcx],20h ;Space after "mtllib" - Most probable
    206. je lbl_TokenMtlLib
    207. cmp byte ptr[rcx],9 ;Tab after "mtllib" - Least probable
    208. je lbl_TokenMtlLib
    209. jmp lbl_FindNextLine ;Junk
    210.  
    211. ;Count material: "mtllib"
    212. lbl_TokenMtlLib:
    213. inc gnTotalMtlLibs
    214. add rcx,6 ;Skip Token
    215. jmp lbl_FindNextLine
    216.  
    217.  
    218.  
    219.  
    220. lbl_FindNextLine:
    221. inc rcx ;Skip previously checked byte
    222. mov rsi,rcx ;pCurrentPosition
    223. ;Do not use rcx to store pCurrentPosition
    224. ;because it is used by vpcmpistri as index
    225.  
    226. lbl_NextXmmword_1:
    227. cmp rsi,gpObjDataEnd
    228. jge lbl_EndOfFile
    229.  
    230. ;Pattern: ASCII code: Carriage Return = 0Dh, Line Feed = 0Ah
    231. mov rax,0Ah ;Chech for LF alone
    232. movq xmm0,rax
    233. ;Compare bytes at [rsi] against pattern in XMM0
    234. ;Mode 0: equal_any, positive polarity, implicit length
    235. vpcmpistri xmm0,xmmword ptr[rsi],0
    236. jz lbl_EndOfFile
    237. jc lbl_EndOfLineFound
    238. add rsi,10h ;Compute the next address to check
    239. jmp lbl_NextXmmword_1
    240. lbl_EndOfLineFound:
    241. ;ECX contains the index of the first found character
    242. add rcx,rsi ;Compute the absolute address
    243. cmp rcx,gpObjDataEnd
    244. jge lbl_EndOfFile
    245. jmp lbl_ReadNextLine
    246.  
    247.  
    248.  
    249.  
    250. lbl_EndOfFile:
    251.  
    252. LOG_TEXT szLogTotalObjects
    253. mov rcx,gnTotalObjects
    254. call WriteDecimalToLog
    255. LOG_TEXT szCRLF
    256.  
    257. LOG_TEXT szLogTotalGroups
    258. mov rcx,gnTotalGroups
    259. call WriteDecimalToLog
    260. LOG_TEXT szCRLF
    261.  
    262. LOG_TEXT szLogTotalSubGroups
    263. mov rcx,gnTotalSubGroups
    264. call WriteDecimalToLog
    265. LOG_TEXT szCRLF
    266.  
    267. LOG_TEXT szLogTotalFaces
    268. mov rcx,gnTotalFaces
    269. call WriteDecimalToLog
    270. LOG_TEXT szCRLF
    271.  
    272. LOG_TEXT szLogTotalVertices
    273. mov rcx,gnTotalVertices
    274. call WriteDecimalToLog
    275. LOG_TEXT szCRLF
    276.  
    277. LOG_TEXT szLogTotalNormals
    278. mov rcx,gnTotalNormals
    279. call WriteDecimalToLog
    280. LOG_TEXT szCRLF
    281.  
    282. LOG_TEXT szLogTotalTextureVectors
    283. mov rcx,gnTotalTextureVectors
    284. call WriteDecimalToLog
    285. LOG_TEXT szCRLF
    286.  
    287. LOG_TEXT szLogTotalMtlLibs
    288. mov rcx,gnTotalMtlLibs
    289. call WriteDecimalToLog
    290. LOG_TEXT szCRLF
    291.  
    292.  
    293.  
    294. ;Success
    295. mov rax,1
    296. jmp lbl_End
    297.  
    298. lbl_WinError:
    299. call SpellWinError
    300. xor rax,rax
    301. ;jmp lbl_End
    302.  
    303. lbl_End:
    304. EPILOG
    305. countObjEntities endp
    306.  
    То есть я большие участки перескакиваю, а там, где надо работать точечно, проверяю каждый байт
     
  8. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    Если я правильно понял, у вас из-за каждого лишнего пробела/таба парсер будет падать, хотя это будет валидный .obj файл.
     
  9. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    Наоборот: vpcmpistri игнорирует и пробелы, и вообще все значения, за исключением тех, что заданы во втором операнде.
    Тоже наоборот: не в проверку валидности (это ответственный участок), а в поиск символов EoL, т.е. LF и CR (где надо быстро проскочить).
    Скалярные инструкцииvpcmpistri
    Loading OBJ fileLoading OBJ file
    OBJ file opened, size: 1653348OBJ file opened, size: 1653344
    RAM size calculated
    Memory Allocating: OK
    RAM allocated
    Loading MTL file
    MTL file opened, size: 1557
    Memory Allocating: OK
    Materials: 7
    MTL loaded successfully
    Objects: 89
    Groups: 89
    SubGroups: 89
    Faces: 17711
    Vertices: 12193Vertices: 12193
    Normals: 12008Normals: 12008
    Combined Vertices: 14909
    Indices: 53133
    Grouping faces by materials
    Material Groups: 7
    Texture vectors: 7525
    Material Libraries Used: 1
    OBJ loaded successfullyOBJ loaded successfully
    Код полностью отрабатывает токены "o", "g", "f", "v", "vn", "vt", "usemtl" и "mtllib"
     

    Вложения:

  10. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    Тогда ваш код гораздо умнее, чем я думал. Например:
    1. Находит первый символ из шаблона (v)
    2. Обрабатывает его
    3. Не возвращается к поиску в этой строке
    4. Сразу ищет конец строки
     
  11. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    Да, метка lbl_ReadNextLine предполагает, что я нахожусь на новой строке.
    Там vpcmpistri ищет токен. Если находит - дорабатывает напильником, и тогда остаток символов в строке (в этой конкретной процедуре) его уже не интересует.
    Он прыгает на второй vpcmpistri, который ищет конец строки.
    И так до gpDataEnd
    --- Сообщение объединено, 16 авг 2026 в 04:19 ---
    Нет. Если решётка стоит в начале строки, то vpcmpistri найдёт её первой и покажет на неё
     
  12. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.008
    Мне почему стало интересно, иногда приходится парсить текстовые файлы.

    Я никогда на практике не использовал vpcmpistri, simd.
    Возник вопрос, можно ли применить для этой функции:
    Код (C):
    1. bool is_meaningful(char ch) {
    2.     return isalnum(ch) || ch == '.' || ch == '-' || ch == '+' || ch == '/' || ch == '_';
    3. }
    Например сделать таблицу-шаблон для символов:
    И проверять ее по 16 символов, или это бред ? Мне кажется это самое узкое место в моем парсинге. По сути ищем символ которого нет в шаблоне. Если simd по 16 символов проверяет, можно сделать парсинг в 16 раз быстрее.
     
  13. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    Проверяет. Операнды vpcmpistri - это xmmword.
    Функцию is_meaningful(...) можно заменить одним интринсиком
    Upd: погорячился. A-Z одним интринсиком не заменишь, но вполне себе разумный цикл этого интринсика организовать можно.
    Другой вопрос: я не гарантирую эффективность, совместимость и т.д.
    Никто не знает, что там в микрокоде:
    с одной стороны - может оказаться, что cmpsb кэшируется эффективнее,
    с другой стороны - супер-пупер vpcmpistri может спровоцировать троттлинг.
    --- Сообщение объединено, 16 авг 2026 в 05:00 ---
    У меня тут чистый эксперимент, на грани стёба. Ё моё: "Москвич" на Вулкане, ещё и на ассемблере.
    По приколу я себе могу это позволить, а вот что-то продаваемое я бы так делать не рискнул
     
    Последнее редактирование: 16 авг 2026 в 05:04
    Mikl___ нравится это.
  14. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    Ни cmpsb, ни xlat сами по себе не решают вопрос, т.к. обращаются к памяти.

    Если бы я постоянно работал со строками, то смотрел бы в сторону кэш-памяти, т.е. группы инструкций PREFETCH.
    Но у меня узкая специализация (3D-графика), поэтому для меня это ненадёжная практика, т.к. я не знаю, что происходит в микрокоде разных моделей и ревизий процессоров Intel и AMD.

    Первое, что бы я сделал - это взял бы среднестатистический текст, с которым Вы работаете, и ранжировал бы символы по вероятности их обнаружения.
    Тогда бы у меня была не таблица 'A'-'Z', а реальная жиза.
    Вот этой таблицей я бы прогрел кэш, закрепил бы его инструкцией PREFETCH, сделал 100500 разных сборок и протестировал бы на разных системах.

    Поскольку моя профессия - это 3D-графика, я балдею от SSE, AVX и FMA, а любое обращение к памяти для меня - это снижение плотности вычислений.
    Ваш E8400 - это Core2Duo, в нём нет SSE4.2, следовательно нет pcmpistri.
    Значит, я бы работал с тем, что есть.
    Ту самую ранжированную таблицу я бы загрузил во все РОН, в крайнем случае - в xmm и не пользовался бы RAM вообще

    RR_08a.jpeg
     
    Mikl___ и Application нравится это.
  15. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    89
    Вы - гений. Вы просто гений!

    Действительно, зачем мне каждый раз проверять WM_CREATE и WM_DESTROY, если они появляются всего один раз за всю жизнь экземпляра приложения?!

    Вот идеальный диспетчер сообщений:
    Код (ASM):
    1. .data
    2. gpWmCreate dq offset wmCreateProc
    3. gpWmDestroy dq offset wmDestroyProc
    4. gpWmSize dq offset wmSizeProc
    5. gpWmClose dq offset wmCloseProc
    6. gpWmCommand dq offset wmCommandProc
    7. LUT dq 1,2,5,10h,111h,0,0,0
    8. .code
    9. WndProc proc
    10. movd xmm0,edx
    11. vpcmpistri xmm0,xmmword ptr[LUT],0Ch
    12. [pWmCreate + rcx*8]
    13. call DefWindowProcA
    14. WndProc endp
    --- Сообщение объединено, 17 авг 2026 в 09:39 ---
    Ещё можно ранжировать таблицу по вероятности:
    Код (ASM):
    1.  
    2. .data
    3. gpWmCommand dq offset wmCommandProc ;Самое вероятное
    4. gpWmSize dq offset wmSizeProc ;Несколько раз
    5. gpWmClose dq offset wmCloseProc ;Один или несколько раз
    6. gpWmDestroy dq offset wmDestroyProc ;Один раз
    7. gpWmCreate dq offset wmCreateProc ;Один раз
    8. LUT dq 111h,5,10h,2,1,0,0,0
    9. .code
    10. WndProc proc
    11. movd xmm0,edx
    12. vpcmpistri xmm0,xmmword ptr[LUT],0Ch
    13. [pWmCommand + rcx*8]
    14. call DefWindowProcA
    15. WndProc endp
    16.  
     
    Последнее редактирование: 17 авг 2026 в 08:17