genx86.pas

Переключить прокрутку окна
Загрузить этот исходный код

{
    Этот исходный текст является частью Продвинутого векторного транслятора.

    Copyright © 2017 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit GenX86;

{$MODE DELPHI,EXTENDEDSYNTAX ON}

interface

uses
    Lang, Utils, TranType;

{$ASMMODE INTEL,CALLING REGISTER,INLINE ON,GOTO ON}
{$H+,I-,J-,M-,Q-,R-,T-}

type
    MemoryLocation = interface;
    RegisterStack = interface;
    MemoryLocationTfasm = class;
    TextGenerator = class;
    TextGenerator64 = class;

    TextGenerator_Class = class of TextGenerator;

    RegistersX86 = class helper for _Object
    public
        { режимы (разрядности) кода }
        const MODE_NONE = 0;
        const MODE_16_BIT = TranslatorType.SIZE_16_BIT;
        const MODE_32_BIT = TranslatorType.SIZE_32_BIT;
        const MODE_64_BIT = TranslatorType.SIZE_64_BIT;
        { GPR 8 бит }
        const R0B   = $00;
        const R1B   = $01;
        const R2B   = $02;
        const R3B   = $03;
        const R4B   = $04;
        const R5B   = $05;
        const R6B   = $06;
        const R7B   = $07;
        const R8B   = $08;
        const R9B   = $09;
        const R10B  = $0a;
        const R11B  = $0b;
        const R12B  = $0c;
        const R13B  = $0d;
        const R14B  = $0e;
        const R15B  = $0f;
        { GPR 16 бит }
        const R0W   = $10;
        const R1W   = $11;
        const R2W   = $12;
        const R3W   = $13;
        const R4W   = $14;
        const R5W   = $15;
        const R6W   = $16;
        const R7W   = $17;
        const R8W   = $18;
        const R9W   = $19;
        const R10W  = $1a;
        const R11W  = $1b;
        const R12W  = $1c;
        const R13W  = $1d;
        const R14W  = $1e;
        const R15W  = $1f;
        { GPR 32 бит }
        const R0D   = $20;
        const R1D   = $21;
        const R2D   = $22;
        const R3D   = $23;
        const R4D   = $24;
        const R5D   = $25;
        const R6D   = $26;
        const R7D   = $27;
        const R8D   = $28;
        const R9D   = $29;
        const R10D  = $2a;
        const R11D  = $2b;
        const R12D  = $2c;
        const R13D  = $2d;
        const R14D  = $2e;
        const R15D  = $2f;
        { GPR 64 бит }
        const R0    = $30;
        const R1    = $31;
        const R2    = $32;
        const R3    = $33;
        const R4    = $34;
        const R5    = $35;
        const R6    = $36;
        const R7    = $37;
        const R8    = $38;
        const R9    = $39;
        const R10   = $3a;
        const R11   = $3b;
        const R12   = $3c;
        const R13   = $3d;
        const R14   = $3e;
        const R15   = $3f;
        { MMX }
        const MM0   = $40;
        const MM1   = $41;
        const MM2   = $42;
        const MM3   = $43;
        const MM4   = $44;
        const MM5   = $45;
        const MM6   = $46;
        const MM7   = $47;
        { FPU }
        const ST0   = $50;
        const ST1   = $51;
        const ST2   = $52;
        const ST3   = $53;
        const ST4   = $54;
        const ST5   = $55;
        const ST6   = $56;
        const ST7   = $57;
        { XMM }
        const XMM0  = $60;
        const XMM1  = $61;
        const XMM2  = $62;
        const XMM3  = $63;
        const XMM4  = $64;
        const XMM5  = $65;
        const XMM6  = $66;
        const XMM7  = $67;
        const XMM8  = $68;
        const XMM9  = $69;
        const XMM10 = $6a;
        const XMM11 = $6b;
        const XMM12 = $6c;
        const XMM13 = $6d;
        const XMM14 = $6e;
        const XMM15 = $6f;
        const XMM16 = $70;
        const XMM17 = $71;
        const XMM18 = $72;
        const XMM19 = $73;
        const XMM20 = $74;
        const XMM21 = $75;
        const XMM22 = $76;
        const XMM23 = $77;
        const XMM24 = $78;
        const XMM25 = $79;
        const XMM26 = $7a;
        const XMM27 = $7b;
        const XMM28 = $7c;
        const XMM29 = $7d;
        const XMM30 = $7e;
        const XMM31 = $7f;
        { YMM }
        const YMM0  = $80;
        const YMM1  = $81;
        const YMM2  = $82;
        const YMM3  = $83;
        const YMM4  = $84;
        const YMM5  = $85;
        const YMM6  = $86;
        const YMM7  = $87;
        const YMM8  = $88;
        const YMM9  = $89;
        const YMM10 = $8a;
        const YMM11 = $8b;
        const YMM12 = $8c;
        const YMM13 = $8d;
        const YMM14 = $8e;
        const YMM15 = $8f;
        const YMM16 = $90;
        const YMM17 = $91;
        const YMM18 = $92;
        const YMM19 = $93;
        const YMM20 = $94;
        const YMM21 = $95;
        const YMM22 = $96;
        const YMM23 = $97;
        const YMM24 = $98;
        const YMM25 = $99;
        const YMM26 = $9a;
        const YMM27 = $9b;
        const YMM28 = $9c;
        const YMM29 = $9d;
        const YMM30 = $9e;
        const YMM31 = $9f;
        { ZMM }
        const ZMM0  = $a0;
        const ZMM1  = $a1;
        const ZMM2  = $a2;
        const ZMM3  = $a3;
        const ZMM4  = $a4;
        const ZMM5  = $a5;
        const ZMM6  = $a6;
        const ZMM7  = $a7;
        const ZMM8  = $a8;
        const ZMM9  = $a9;
        const ZMM10 = $aa;
        const ZMM11 = $ab;
        const ZMM12 = $ac;
        const ZMM13 = $ad;
        const ZMM14 = $ae;
        const ZMM15 = $af;
        const ZMM16 = $b0;
        const ZMM17 = $b1;
        const ZMM18 = $b2;
        const ZMM19 = $b3;
        const ZMM20 = $b4;
        const ZMM21 = $b5;
        const ZMM22 = $b6;
        const ZMM23 = $b7;
        const ZMM24 = $b8;
        const ZMM25 = $b9;
        const ZMM26 = $ba;
        const ZMM27 = $bb;
        const ZMM28 = $bc;
        const ZMM29 = $bd;
        const ZMM30 = $be;
        const ZMM31 = $bf;
        { альтернативные названия регистров }
        const RAX   = R0;
        const RCX   = R1;
        const RDX   = R2;
        const RBX   = R3;
        const RSP   = R4;
        const RBP   = R5;
        const RSI   = R6;
        const RDI   = R7;
        const EAX   = R0D;
        const ECX   = R1D;
        const EDX   = R2D;
        const EBX   = R3D;
        const ESP   = R4D;
        const EBP   = R5D;
        const ESI   = R6D;
        const EDI   = R7D;
        const AX    = R0W;
        const CX    = R1W;
        const DX    = R2W;
        const BX    = R3W;
        const SP    = R4W;
        const BP    = R5W;
        const SI    = R6W;
        const DI    = R7W;
        const AL    = R0B;
        const CL    = R1B;
        const DL    = R2B;
        const BL    = R3B;
        const SPL   = R4B;
        const BPL   = R5B;
        const SIL   = R6B;
        const DIL   = R7B;
        const ST    = ST0;
        { XMM subtypes (combination with XMMi, YMMi or ZMMi need) }
        const XPINT    = $0000; // 4 packed int
        const XPLONG   = $0100; // 2 packed long
        const XPFLOAT  = $0200; // 4 packed float
        const XPDOUBLE = $0300; // 2 packed double
        const XSINT    = $0400; // 1 scalar int
        const XSLONG   = $0500; // 1 scalar long
        const XSFLOAT  = $0600; // 1 scalar float
        const XSDOUBLE = $0700; // 1 scalar double
        const XMASK    = $0700;
        { memory size modifiers }
        const MNONE   = 0;
        const MBYTE   = 1;
        const MWORD   = 2;
        const MDWORD  = 4;
        const MQWORD  = 8;
        const MTBYTE  = 10;
        const MSHORT  = MWORD;
        const MINT    = MDWORD;
        const MLONG   = MQWORD;
        const MFLOAT  = MDWORD;
        const MDOUBLE = MQWORD;
        const MREAL   = MTBYTE;
        { register-relative methods }
        class function isRegisterGP(reg: int): boolean;
        class function isRegisterXMM(reg: int): boolean;
        class function isRegisterYMM(reg: int): boolean;
        class function isRegisterZMM(reg: int): boolean;
        class function isRegisterFPU(reg: int): boolean;
        class function isRegisterMMX(reg: int): boolean;
        class function getRegisterSize(reg: int): int;
        class function getCommonRegister(reg: int): int;
    end;

    MemoryLocation = interface(_Interface) ['{CE5EA53F-65D8-4177-B5CD-D1252ADC30E4}']
        function getRegisterSource(): int;
        function memoryToString(modifier: int; displacement: int): String;
    end;

    RegisterStack = interface(_Interface) ['{CE5EA53F-65D8-4177-B5CD-D1252ADC30E5}']
        procedure clear();
        procedure pushReg(reg: int);
        procedure popRegs(count: int);
        procedure storeRegs(count: int; generator: TextGenerator);
        procedure restoreRegs(generator: TextGenerator);
        procedure restoreRegsWithoutCodeGeneration();
        procedure deallocateReg(generator: TextGenerator);
        procedure deallocateRegWithoutCodeGeneration();
        function isUsedRegister(reg: int): boolean;
        function getNextUsedGPR(regGPR: int): int;
        function getNextUsedXMM(regXMM: int): int;
        function getNextUsedMMX(regMMX: int): int;
        function getRegAt(index: int): int;
        function base(): int;
        function size(): int;
        function changeToGPR16bit(index: int): int;
        function changeToGPR32bit(index: int): int;
        function changeToGPR64bit(index: int): int;
        function changeToXMM(index, xtype: int): int;
        function changeToYMM(index, xtype: int): int;
        function changeToZMM(index, xtype: int): int;
        function allocateGPR16bit(generator: TextGenerator): int;
        function allocateGPR32bit(generator: TextGenerator): int;
        function allocateGPR64bit(generator: TextGenerator): int;
        function allocateGPRForArray(generator: TextGenerator): int;
        function allocateGPRForIndex(generator: TextGenerator): int;
        function allocateGPRForPointer(generator: TextGenerator): int;
        function allocateXMM(xtype: int; generator: TextGenerator): int;
        function allocateYMM(xtype: int; generator: TextGenerator): int;
        function allocateZMM(xtype: int; generator: TextGenerator): int;
        function allocateFPU(count: int; generator: TextGenerator): int;
        function allocateMMX(generator: TextGenerator): int;
    end;

    MemoryLocationTfasm = class(RefCountInterfacedObject, MemoryLocation)
    public
        constructor create(generator: TextGenerator; regSrc: int;
                const labelBase: String); overload;
        constructor create(generator: TextGenerator; regSrc: int;
                regBase: int; const labelOffset: String); overload;
        constructor create(generator: TextGenerator; regSrc: int;
                regBase, regIndex: int; const labelOffset: String); overload;
        constructor create(generator: TextGenerator; regSrc: int;
                regBase, regIndex, scale: int; const labelOffset: String); overload;
        function getRegisterSource(): int; virtual;
        function memoryToString(modifier: int; offset: int): String; virtual;
    strict private
        mode: int;
        scale: int;
        regSrc: int;
        regBase: int;
        regIndex: int;
        generator: TextGenerator;
        labelName: String;
    end;

    TextGenerator = class(Vector)
    public
        const EXIT_RET = 0;
        const EXIT_RETF = 1;
        const EXIT_CALL = 4;
        const USE16 = 'use16';
        const USE32 = 'use32';
        const USE64 = 'use64';
        class function isNeedHeapSize(): boolean; virtual;
        class function isNeedStackSize(): boolean; virtual;
        class function isNeedExitMethod(): boolean; virtual;

    public
        constructor create(); virtual;
        function toString(): AnsiString; override;
        procedure clear(); override;
        procedure optimize(); virtual;
        procedure beginCodeSection(); virtual;
        procedure beginDataSection(); virtual;
        procedure beginPoolSection(); virtual;
        procedure writeEmptyLine(); virtual;
        procedure writeText(const text: String); virtual;
        procedure writeAlignGlobal(align: int); virtual;
        procedure writeAlignLocal(align: int); virtual;
        procedure writeDirectives(mode, org: int; const entry: String); virtual;
        procedure writeProgrammeTail(); virtual;
        procedure writeAssembler(const text: String); virtual;
        procedure writeCommentToLineEnd(const commentText: String); virtual;
        procedure writeCommentWithIdent(const commentText: String); virtual;
        procedure writeEquality(const macroName, macroValue: String); virtual;
        procedure writeLabelGlobal(const labelName: String); virtual;
        procedure writeLabelLong(const labelName: String); virtual;
        procedure writeLabelShort(const labelName: String); virtual;
        procedure writeLabelRelative(const labelName: String; regBase, offset: int); virtual;
        procedure writeInstruction(const mnemonic: String); overload; virtual;
        procedure writeInstruction(const mnemonic, operand1: String); overload; virtual;
        procedure writeInstruction(const mnemonic, operand1, operand2: String); overload; virtual;
        procedure writeInstruction(const mnemonic, operand1, operand2,
                operand3: String); overload; virtual;
        procedure writeInstruction(const mnemonic, operand1, operand2, operand3,
                operand4: String); overload; virtual;
        procedure writeInstruction(const mnemonic: String;
                const operands: String_Array1d); overload; virtual;
        function labelCurrentOffsetToString(offset: int): String; virtual;
        function labelRelativeToString(const labelName: String; offset: int): String; virtual;
        function labelRelativeAnotherToString(const labelName, another: String;
                offset: int): String; virtual;
        function registerToString(reg: int): String; virtual;
        function memoryToStringDecOffset(modifier: int; const labelBase: String;
                offset: int): String; virtual;
        function memoryToString(modifier: int; regBase: int;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; regBase: int; regIndex: int;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; regBase: int; regIndex, scale: int;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String; regIndex: int;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String; regIndex, scale: int;
                offset: int): String; overload; virtual;
        function memoryToString(modifier: int; regBase: int;
                const labelOffset: String; offset: int): String; overload; virtual;
        function memoryToString(modifier: int; regBase: int; regIndex: int;
                const labelOffset: String; offset: int): String; overload; virtual;
        function memoryToString(modifier: int; regBase: int; regIndex, scale: int;
                const labelOffset: String; offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String;
                const labelOffset: String; offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String; regIndex: int;
                const labelOffset: String; offset: int): String; overload; virtual;
        function memoryToString(modifier: int; const labelBase: String; regIndex, scale: int;
                const labelOffset: String; offset: int): String; overload; virtual;
        function immediateToString(value: int): String; virtual;
        function immediateToStringByte(value: int): String; virtual;
        function immediateToStringShort(value: int): String; virtual;
        function immediateToStringInt(value: int): String; virtual;
        function immediateToStringLong(value: long): String; virtual;
    protected
        fldExitMethod: int;
        procedure setHeapSize(heapSize: int); virtual;
        procedure setStackSize(stackSize: int); virtual;
        procedure setExitMethod(exitMethod: int); virtual;
        function getHeapSize(): int; virtual;
        function getStackSize(): int; virtual;
        function offsetToDecString(offset: int): String; virtual;
        function offsetToHexString(offset: int): String; virtual;
        function modifierToString(modifier: int): String; virtual;
    private
        labelWrited: boolean;
    strict private
        fldHeapSize: int;
        fldStackSize: int;
    public
        property heapSize: int read getHeapSize write setHeapSize;
        property stackSize: int read getStackSize write setStackSize;
        property exitMethod: int read fldExitMethod write setExitMethod;
    end;

    TextGenerator64 = class(TextGenerator)
    public
        procedure writeDirectives(mode, org: int; const entry: String); override;
        function registerToString(reg: int): String; override;
    end;

implementation

{ RegistersX86 }

class function RegistersX86.isRegisterGP(reg: int): boolean;
begin
    case reg and $ff of
    R0B..R15:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.isRegisterXMM(reg: int): boolean;
begin
    case reg and $ff of
    XMM0..XMM31:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.isRegisterYMM(reg: int): boolean;
begin
    case reg and $ff of
    XMM0..YMM31:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.isRegisterZMM(reg: int): boolean;
begin
    case reg and $ff of
    XMM0..ZMM31:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.isRegisterFPU(reg: int): boolean;
begin
    case reg and $ff of
    ST0..ST7:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.isRegisterMMX(reg: int): boolean;
begin
    case reg and $ff of
    MM0..MM7:
        result := true;
    else
        result := false;
    end;
end;

class function RegistersX86.getRegisterSize(reg: int): int;
begin
    case reg and $ff of
    R0B..R15B:
        result := 8;
    R0W..R15W:
        result := 16;
    R0D..R15D:
        result := 32;
    R0..R15, MM0..MM7:
        result := 64;
    ST0..ST7:
        result := 80;
    XMM0..XMM31:
        result := 128;
    YMM0..YMM31:
        result := 256;
    ZMM0..ZMM31:
        result := 512;
    else
        result := 0;
    end;
end;

class function RegistersX86.getCommonRegister(reg: int): int;
begin
    case reg and $ff of
    R0B..R15:
        result := R0 + (reg and $0f);
    MM0..MM7, ST0..ST7:
        result := ST0 + (reg and $0f);
    XMM0..ZMM31:
        result := ZMM0 + (reg and $1f);
    end;
end;

{ MemoryLocationTfasm }

constructor MemoryLocationTfasm.create(generator: TextGenerator; regSrc: int;
        const labelBase: String);
begin
    inherited create();
    self.mode := 0;
    self.scale := 1;
    self.regSrc := regSrc;
    self.regBase := -1;
    self.regIndex := -1;
    self.generator := generator;
    self.labelName := labelBase;
end;

constructor MemoryLocationTfasm.create(generator: TextGenerator; regSrc: int;
        regBase: int; const labelOffset: String);
begin
    inherited create();
    self.mode := 1;
    self.scale := 1;
    self.regSrc := regSrc;
    self.regBase := regBase;
    self.regIndex := -1;
    self.generator := generator;
    self.labelName := labelOffset;
end;

constructor MemoryLocationTfasm.create(generator: TextGenerator; regSrc: int;
        regBase, regIndex: int; const labelOffset: String);
begin
    inherited create();
    self.mode := 2;
    self.scale := 1;
    self.regSrc := regSrc;
    self.regBase := regBase;
    self.regIndex := regIndex;
    self.generator := generator;
    self.labelName := labelOffset;
end;

constructor MemoryLocationTfasm.create(generator: TextGenerator; regSrc: int;
        regBase, regIndex, scale: int; const labelOffset: String);
begin
    inherited create();
    self.mode := 2;
    self.scale := scale;
    self.regSrc := regSrc;
    self.regBase := regBase;
    self.regIndex := regIndex;
    self.generator := generator;
    self.labelName := labelOffset;
end;

function MemoryLocationTfasm.getRegisterSource(): int;
begin
    result := regSrc;
end;

function MemoryLocationTfasm.memoryToString(modifier: int; offset: int): String;
begin
    case mode of
     0: result := generator.memoryToString(modifier, labelName, offset);
     1: result := generator.memoryToString(modifier, regBase, labelName, offset);
     2: result := generator.memoryToString(modifier, regBase, regIndex, scale, labelName, offset);
    else
        result := '';
    end;
end;

{ TextGenerator }

class function TextGenerator.isNeedHeapSize(): boolean;
begin
    result := false;
end;

class function TextGenerator.isNeedStackSize(): boolean;
begin
    result := false;
end;

class function TextGenerator.isNeedExitMethod(): boolean;
begin
    result := true;
end;

constructor TextGenerator.create();
begin
    inherited create();
    self.labelWrited := false;
end;

function TextGenerator.toString(): AnsiString;
var
    i: int;
    limit: int;
    element: _Interface;
    representation: String;
begin
    result := '';
    limit := size() - 1;
    for i := 0 to limit do begin
        element := elementAt(i);
        if element <> nil then begin
            representation := element.toString();
        end else begin
            representation := '';
        end;
        result := result + (representation + LINE_ENDING);
    end;
end;

procedure TextGenerator.clear();
begin
    inherited clear();
    labelWrited := false;
end;

procedure TextGenerator.optimize();
const
    POP = #$09#$09'pop'#$09;
    PUSH = #$09#$09'push'#$09;
var
    writed: boolean;
    i: int;
    limit: int;
    e1: _Interface;
    e2: _Interface;
    s1: String;
    s2: String;
    r1: String;
    r2: String;

    procedure remove(); inline;
    begin
        removeElementAt(i + 1);
        removeElementAt(i);
        dec(limit, 2);
        writed := true;
        e2 := elementAt(i);
        if e2 <> nil then begin
            s2 := e2.toString();
        end else begin
            s2 := '';
        end;
    end;

begin
    limit := size() - 1;
    repeat
        writed := false;
        e2 := elementAt(limit);
        if e2 <> nil then begin
            s2 := e2.toString();
        end else begin
            s2 := '';
        end;
        for i := limit - 1 downto 0 do begin
            e1 := elementAt(i);
            if e1 <> nil then begin
                s1 := e1.toString();
            end else begin
                s1 := '';
            end;
            if stringStartsWith(POP, s1) and stringStartsWith(PUSH, s2) then begin
                { pop reg, push reg }
                r1 := copy(s1, length(POP) + 1, length(s1));
                r2 := copy(s2, length(PUSH) + 1, length(s2));
                if r1 = r2 then begin
                    remove();
                    continue;
                end;
            end;
            if stringStartsWith(PUSH, s1) and stringStartsWith(POP, s2) then begin
                { push reg, pop reg }
                r1 := copy(s1, length(PUSH) + 1, length(s1));
                r2 := copy(s2, length(POP) + 1, length(s2));
                if r1 = r2 then begin
                    remove();
                    continue;
                end;
            end;
            s2 := s1;
        end;
    until not writed;
end;

procedure TextGenerator.beginCodeSection();
begin
end;

procedure TextGenerator.beginDataSection();
begin
end;

procedure TextGenerator.beginPoolSection();
begin
end;

procedure TextGenerator.writeEmptyLine();
begin
    addElement('');
    labelWrited := false;
end;

procedure TextGenerator.writeText(const text: String);
begin
    addElement(text);
    labelWrited := false;
end;

procedure TextGenerator.writeAlignGlobal(align: int);
begin
    addElement('align ' + immediateToString(align));
    labelWrited := false;
end;

procedure TextGenerator.writeAlignLocal(align: int);
begin
    addElement(#$09'align ' + immediateToString(align));
    labelWrited := false;
end;

procedure TextGenerator.writeDirectives(mode, org: int; const entry: String);
begin
    case mode of
    MODE_16_BIT: begin
        addElement(USE16);
        addElement('org ' + immediateToStringShort(org));
    end;
    MODE_32_BIT: begin
        addElement(USE32);
        addElement('org ' + immediateToStringInt(org));
    end;
    MODE_64_BIT: begin
        addElement(USE64);
        { игнорируем org: код позиционно-независимый }
    end;
    end;
    labelWrited := false;
end;

procedure TextGenerator.writeProgrammeTail();
begin
end;

procedure TextGenerator.writeAssembler(const text: String);
var
    index: int;
    element: _Interface;
    line: String;
begin
    index := size() - 1;
    if labelWrited and (index >= 0) then begin
        element := elementAt(index);
        if element <> nil then begin
            line := element.toString();
        end else begin
            line := '';
        end;
        setElementAt(index, line + text);
    end else begin
        addElement(#$09#$09 + text);
    end;
    labelWrited := false;
end;

procedure TextGenerator.writeCommentToLineEnd(const commentText: String);
var
    c: int;
    index: int;
    element: _Interface;
    line: String;
begin
    index := size() - 1;
    if index >= 0 then begin
        element := elementAt(index);
        if element <> nil then begin
            line := element.toString();
        end else begin
            line := '';
        end;
        c := length(line);
        if (c <= 0) or (int(line[c]) <= $20) then begin
            line := line + '; ' + commentText;
        end else begin
            line := line + ' ; ' + commentText;
        end;
        setElementAt(index, line);
    end else begin
        addElement('; ' + commentText);
    end;
    labelWrited := false;
end;

procedure TextGenerator.writeCommentWithIdent(const commentText: String);
begin
    writeAssembler('; ' + commentText);
end;

procedure TextGenerator.writeEquality(const macroName, macroValue: String);
begin
    addElement(macroName + ' equ ' + macroValue);
    labelWrited := false;
end;

procedure TextGenerator.writeLabelGlobal(const labelName: String);
begin
    addElement(labelName + ':');
    labelWrited := false;
end;

procedure TextGenerator.writeLabelLong(const labelName: String);
var
    c: int;
    text: String;
begin
    c := length(labelName);
    if c < 7 then begin
        text := labelName + ':'#$09#$09;
    end else
    if c < 15 then begin
        text := labelName + ':'#$09;
    end else begin
        text := labelName + ':';
    end;
    addElement(text);
    labelWrited := true;
end;

procedure TextGenerator.writeLabelShort(const labelName: String);
var
    text: String;
begin
    if length(labelName) < 7 then begin
        text := #$09 + labelName + ':'#$09;
    end else begin
        text := #$09 + labelName + ':';
    end;
    addElement(text);
    labelWrited := true;
end;

procedure TextGenerator.writeLabelRelative(const labelName: String; regBase, offset: int);
begin
    writeAssembler('label'#$09 + labelName + ' at ' +
            registerToString(regBase) + offsetToHexString(offset));
end;

procedure TextGenerator.writeInstruction(const mnemonic: String);
begin
    writeAssembler(mnemonic);
end;

procedure TextGenerator.writeInstruction(const mnemonic, operand1: String);
begin
    writeInstruction(mnemonic, String_Array1d_create([
        operand1
    ]));
end;

procedure TextGenerator.writeInstruction(const mnemonic, operand1, operand2: String);
begin
    writeInstruction(mnemonic, String_Array1d_create([
        operand1, operand2
    ]));
end;

procedure TextGenerator.writeInstruction(const mnemonic, operand1, operand2, operand3: String);
begin
    writeInstruction(mnemonic, String_Array1d_create([
        operand1, operand2, operand3
    ]));
end;

procedure TextGenerator.writeInstruction(const mnemonic, operand1, operand2, operand3,
        operand4: String);
begin
    writeInstruction(mnemonic, String_Array1d_create([
        operand1, operand2, operand3, operand4
    ]));
end;

procedure TextGenerator.writeInstruction(const mnemonic: String; const operands: String_Array1d);
var
    i: int;
    limit: int;
    instruction: String;
begin
    limit := length(operands) - 1;
    if limit >= 0 then begin
        if length(mnemonic) < 8 then begin
            instruction := mnemonic + #$09;
        end else begin
            instruction := mnemonic + #$20;
        end;
        for i := 0 to limit do begin
            instruction := instruction + operands[i];
            if i < limit then begin
                instruction := instruction + ', ';
            end;
        end;
        writeAssembler(instruction);
        exit;
    end;
    writeAssembler(mnemonic);
end;

function TextGenerator.labelCurrentOffsetToString(offset: int): String;
begin
    result := '$' + offsetToHexString(offset);
end;

function TextGenerator.labelRelativeToString(const labelName: String; offset: int): String;
begin
    result := labelName + offsetToHexString(offset) + '-$';
end;

function TextGenerator.labelRelativeAnotherToString(const labelName, another: String;
        offset: int): String;
begin
    if length(another) > 0 then begin
        result := labelName + offsetToHexString(offset) + '-' + another;
    end else begin
        result := labelName + offsetToHexString(offset) + '-$';
    end;
end;

function TextGenerator.registerToString(reg: int): String;
begin
    case reg and $ff of
    R0B: result := 'al';
    R1B: result := 'cl';
    R2B: result := 'dl';
    R3B: result := 'bl';
    R4B: result := 'spl';
    R5B: result := 'bpl';
    R6B: result := 'sil';
    R7B: result := 'dil';
    R8B..R15B: result := 'r' + intToString(reg and $0f) + 'b';
    R0W: result := 'ax';
    R1W: result := 'cx';
    R2W: result := 'dx';
    R3W: result := 'bx';
    R4W: result := 'sp';
    R5W: result := 'bp';
    R6W: result := 'si';
    R7W: result := 'di';
    R8W..R15W: result := 'r' + intToString(reg and $0f) + 'w';
    R0D: result := 'eax';
    R1D: result := 'ecx';
    R2D: result := 'edx';
    R3D: result := 'ebx';
    R4D: result := 'esp';
    R5D: result := 'ebp';
    R6D: result := 'esi';
    R7D: result := 'edi';
    R8D..R15D: result := 'r' + intToString(reg and $0f) + 'd';
    R0: result := 'rax';
    R1: result := 'rcx';
    R2: result := 'rdx';
    R3: result := 'rbx';
    R4: result := 'rsp';
    R5: result := 'rbp';
    R6: result := 'rsi';
    R7: result := 'rdi';
    R8..R15: result := 'r' + intToString(reg and $0f);
    MM0..MM7: result := 'mm' + intToString(reg and $0f);
    ST0..ST7: result := 'st' + intToString(reg and $0f);
    XMM0..XMM31: result := 'xmm' + intToString(reg and $1f);
    YMM0..YMM31: result := 'ymm' + intToString(reg and $1f);
    ZMM0..ZMM31: result := 'zmm' + intToString(reg and $1f);
    else result := 'invalid register[$' + intToHexString(reg and $ff) + ']';
    end;
end;

function TextGenerator.memoryToStringDecOffset(modifier: int; const labelBase: String;
        offset: int): String;
begin
    result := modifierToString(modifier) + '[' + labelBase + offsetToDecString(offset) + ']';
end;

function TextGenerator.memoryToString(modifier: int; regBase: int;
        offset: int): String;
begin
    result := modifierToString(modifier) + '[' + registerToString(regBase) +
            offsetToHexString(offset) + ']';
end;

function TextGenerator.memoryToString(modifier: int; regBase: int; regIndex: int;
        offset: int): String;
begin
    result := memoryToString(modifier, regBase, regIndex, 1, offset);
end;

function TextGenerator.memoryToString(modifier: int; regBase: int; regIndex, scale: int;
        offset: int): String;
begin
    case scale of
     1: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + offsetToHexString(offset) + ']';
     2: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*2' + offsetToHexString(offset) + ']';
     4: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*4' + offsetToHexString(offset) + ']';
     8: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*8' + offsetToHexString(offset) + ']';
    else
        result := 'invalid scale[' + intToString(scale) + ']';
    end;
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String;
        offset: int): String;
begin
    result := modifierToString(modifier) + '[' + labelBase + offsetToHexString(offset) + ']';
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String; regIndex: int;
        offset: int): String;
begin
    result := memoryToString(modifier, labelBase, regIndex, 1, offset);
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String; regIndex, scale: int;
        offset: int): String;
var
    sBase: String;
begin
    if length(labelBase) > 0 then begin
        sBase := labelBase + '+';
    end else begin
        sBase := '';
    end;
    case scale of
     1: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + offsetToHexString(offset) + ']';
     2: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*2' + offsetToHexString(offset) + ']';
     4: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*4' + offsetToHexString(offset) + ']';
     8: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*8' + offsetToHexString(offset) + ']';
    else
        result := 'invalid scale[' + intToString(scale) + ']';
    end;
end;

function TextGenerator.memoryToString(modifier: int; regBase: int; const labelOffset: String;
        offset: int): String;
begin
    if length(labelOffset) > 0 then begin
        result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                labelOffset + offsetToHexString(offset) + ']';
    end else begin
        result := modifierToString(modifier) + '[' + registerToString(regBase) +
                offsetToHexString(offset) + ']';
    end;
end;

function TextGenerator.memoryToString(modifier: int; regBase: int; regIndex: int;
        const labelOffset: String; offset: int): String;
begin
    result := memoryToString(modifier, regBase, regIndex, 1, labelOffset, offset);
end;

function TextGenerator.memoryToString(modifier: int; regBase: int; regIndex, scale: int;
        const labelOffset: String; offset: int): String;
var
    sOffset: String;
begin
    if length(labelOffset) > 0 then begin
        sOffset := '+' + labelOffset;
    end else begin
        sOffset := '';
    end;
    case scale of
     1: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + sOffset + offsetToHexString(offset) + ']';
     2: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*2' + sOffset + offsetToHexString(offset) + ']';
     4: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*4' + sOffset + offsetToHexString(offset) + ']';
     8: result := modifierToString(modifier) + '[' + registerToString(regBase) + '+' +
                registerToString(regIndex) + '*8' + sOffset + offsetToHexString(offset) + ']';
    else
        result := 'invalid scale[' + intToString(scale) + ']';
    end;
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String;
        const labelOffset: String; offset: int): String;
begin
    if (length(labelBase) > 0) and (length(labelOffset) > 0) then begin
        result := modifierToString(modifier) + '[' + labelBase + '+' + labelOffset +
                offsetToHexString(offset) + ']';
    end else begin
        result := modifierToString(modifier) + '[' + labelBase + labelOffset +
                offsetToHexString(offset) + ']';
    end;
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String; regIndex: int;
        const labelOffset: String; offset: int): String;
begin
    result := memoryToString(modifier, labelBase, regIndex, 1, labelOffset, offset);
end;

function TextGenerator.memoryToString(modifier: int; const labelBase: String; regIndex, scale: int;
        const labelOffset: String; offset: int): String;
var
    sBase: String;
    sOffset: String;
begin
    if length(labelBase) > 0 then begin
        sBase := labelBase + '+';
    end else begin
        sBase := '';
    end;
    if length(labelOffset) > 0 then begin
        sOffset := '+' + labelOffset;
    end else begin
        sOffset := '';
    end;
    case scale of
     1: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + sOffset + offsetToHexString(offset) + ']';
     2: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*2' + sOffset + offsetToHexString(offset) + ']';
     4: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*4' + sOffset + offsetToHexString(offset) + ']';
     8: result := modifierToString(modifier) + '[' + sBase +
                registerToString(regIndex) + '*8' + sOffset + offsetToHexString(offset) + ']';
    else
        result := 'invalid scale[' + intToString(scale) + ']';
    end;
end;

function TextGenerator.immediateToString(value: int): String;
begin
    case value of
    -$80000000..-$00010000:
        result := '-$' + intToHexString(-value);
    -$0000ffff..-$00000100:
        result := '-$' + shortToHexString(-value);
    -$000000ff..-$00000001:
        result := '-$' + byteToHexString(-value);
    +$00000000..+$000000ff:
        result := '$' + byteToHexString(value);
    +$00000100..+$0000ffff:
        result := '$' + shortToHexString(value);
    else
        result := '$' + intToHexString(value);
    end;
end;

function TextGenerator.immediateToStringByte(value: int): String;
begin
    result := '$' + byteToHexString(value);
end;

function TextGenerator.immediateToStringShort(value: int): String;
begin
    result := '$' + shortToHexString(value);
end;

function TextGenerator.immediateToStringInt(value: int): String;
begin
    result := '$' + intToHexString(value);
end;

function TextGenerator.immediateToStringLong(value: long): String;
begin
    result := '$' + longToHexString(value);
end;

procedure TextGenerator.setHeapSize(heapSize: int);
begin
    self.fldHeapSize := heapSize;
end;

procedure TextGenerator.setStackSize(stackSize: int);
begin
    self.fldStackSize := stackSize;
end;

procedure TextGenerator.setExitMethod(exitMethod: int);
begin
    self.fldExitMethod := exitMethod;
end;

function TextGenerator.getHeapSize(): int;
begin
    result := fldHeapSize;
end;

function TextGenerator.getStackSize(): int;
begin
    result := fldStackSize;
end;

function TextGenerator.offsetToDecString(offset: int): String;
begin
    case offset of
    -$80000000..-$00000001:
        result := intToString(offset);
    +$00000001..+$7fffffff:
        result := '+' + intToString(offset);
    else
        result := '';
    end;
end;

function TextGenerator.offsetToHexString(offset: int): String;
begin
    case offset of
    -$80000000..-$00010000:
        result := '-$' + intToHexString(-offset);
    -$0000ffff..-$00000100:
        result := '-$' + shortToHexString(-offset);
    -$000000ff..-$00000001:
        result := '-$' + byteToHexString(-offset);
    +$00000001..+$000000ff:
        result := '+$' + byteToHexString(offset);
    +$00000100..+$0000ffff:
        result := '+$' + shortToHexString(offset);
    +$00010000..+$7fffffff:
        result := '+$' + intToHexString(offset);
    else
        result := '';
    end;
end;

function TextGenerator.modifierToString(modifier: int): String;
begin
    case modifier of
    MNONE:
        result := '';
    MBYTE:
        result := 'byte';
    MWORD:
        result := 'word';
    MDWORD:
        result := 'dword';
    MQWORD:
        result := 'qword';
    MTBYTE:
        result := 'tbyte';
    else
        result := 'invalid modifier[$' + intToHexString(modifier) + ']';
    end;
end;

{ TextGenerator64 }

procedure TextGenerator64.writeDirectives(mode, org: int; const entry: String);
var
    i: int;
begin
    inherited writeDirectives(mode, org, entry);
    writeEmptyLine();
    for i := 0 to 7 do begin
        if (i <= 3) or (i >= 6) then begin
            writeEquality('r' + intToString(i), inherited registerToString(R0 + i));
        end;
    end;
    for i := 0 to 7 do begin
        writeEquality('r' + intToString(i) + 'd', inherited registerToString(R0D + i));
    end;
    for i := 0 to 7 do begin
        writeEquality('r' + intToString(i) + 'w', inherited registerToString(R0W + i));
    end;
    for i := 0 to 7 do begin
        writeEquality('r' + intToString(i) + 'b', inherited registerToString(R0B + i));
    end;
end;

function TextGenerator64.registerToString(reg: int): String;
begin
    case reg and $ff of
    R0B..R15B:
        result := 'r' + intToString(reg and $0f) + 'b';
    R0W..R15W:
        result := 'r' + intToString(reg and $0f) + 'w';
    R0D..R15D:
        result := 'r' + intToString(reg and $0f) + 'd';
    R4: result := 'rsp';
    R5: result := 'rbp';
    R0..R3, R6..R15:
        result := 'r' + intToString(reg and $0f);
    else
        result := inherited registerToString(reg);
    end;
end;

end.