В последнее время занимался продумыванием и переписыванием .td файлов, в которых описываются все инструкции и регистры процессора Z80. Это позволяет многие упрощения (lowering) реализовать автоматически, т.е. преобразовывать команды llvm в команды процессора Z80 лишь путем описания в .td файлах, что очень удобно и упрощает разработку. Однако не для всех инструкций Z80 есть аналоги в llvm и наоборот не все llvm команды могут быть нативно выполнены на Z80. Для вторых создаются функции, которые заменяют llvm инструкцию на цепочку команд Z80. С первыми бывает немного сложнее, особенно если хочется их использовать для генерации более компактного кода. Поэтому оптимизацией никакой на данном этапе я не занимаюсь. Сейчас просто покажу пару примеров того, что уже может быть скомпилировано.
Пример №1:
После генерации llvm кода clang'ом:Код:unsigned char test(bool useFirst, unsigned char first, unsigned char second) { return (useFirst) ? first : second; }
После генерации кода Z80 утилитой llc (аргументы передаются в регистрах A, B, C по порядку):Код:; ModuleID = 'test.cpp' target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16" target triple = "z80" define i8 @_Z4testbhh(i1 %useFirst, i8 %first, i8 %second) nounwind readnone { entry: %cond = select i1 %useFirst, i8 %first, i8 %second ret i8 %cond }
Пример №2:Код:.file "test.ll" .text .globl _Z4testbhh .type _Z4testbhh,@function _Z4testbhh: ; @_Z4testbhh ; BB#0: ; %entry and 1 cp 0 jp nz, .BB0_2 ; BB#1: ; %entry ld b, c .BB0_2: ; %entry ld a, b ret .tmp0: .size _Z4testbhh, .tmp0-_Z4testbhh
После генерации llvm кода clang'ом:Код:unsigned char test(unsigned char a, unsigned char b) { return (b^0xFF) + (a&0x0F); }
После генерации кода Z80 утилитой llc (аргументы передаются в регистрах A, B по порядку):Код:; ModuleID = 'test.cpp' target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16" target triple = "z80" define i8 @_Z4testhh(i8 %a, i8 %b) nounwind readnone { entry: %xor = xor i8 %b, -1 %and = and i8 %a, 15 %add = add i8 %and, %xor ret i8 %add }
В данный момент осталось дописать команды условных и прямых переходов. Замечу, что на данный момент везде используются переходы JP, что также связано отказом от оптимизации на данный момент. В дальнейшем добавлю проход для генерации JR переходов.Код:.file "test.ll" .text .globl _Z4testhh .type _Z4testhh,@function _Z4testhh: ; @_Z4testhh ; BB#0: ; %entry and 15 ld c, a ld a, b cpl ld b, a ld a, c add a, b ret .tmp0: .size _Z4testhh, .tmp0-_Z4testhh
Ну и самый пока неоднозначный для меня момент это работа с памятью через регистры. Очень не хочется все упрощения делать вручную, да и не обязательно это, но как это лучше реализовать в .td файлах пока думаю.
На этом пока все. Если у кого-то есть какие-то вопросы или пожелания, говорите.




Ответить с цитированием
Размещение рекламы на форуме способствует его дальнейшему развитию 

