| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978 | {    Copyright (c) 1998-2002 by Florian Klaempfl    Some basic types and constants for the code generation    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************}{# This unit exports some types which are used across the code generator }unit cgbase;{$i fpcdefs.inc}interface    uses      globtype,      symconst;    type       { Location types where value can be stored }       TCGLoc=(         LOC_INVALID,      { added for tracking problems}         LOC_VOID,         { no value is available }         LOC_CONSTANT,     { constant value }         LOC_JUMP,         { boolean results only, jump to false or true label }         LOC_FLAGS,        { boolean results only, flags are set }         LOC_REGISTER,     { in a processor register }         LOC_CREGISTER,    { Constant register which shouldn't be modified }         LOC_FPUREGISTER,  { FPU stack }         LOC_CFPUREGISTER, { if it is a FPU register variable on the fpu stack }         LOC_MMXREGISTER,  { MMX register }         { MMX register variable }         LOC_CMMXREGISTER,         { multimedia register }         LOC_MMREGISTER,         { Constant multimedia reg which shouldn't be modified }         LOC_CMMREGISTER,         { contiguous subset of bits of an integer register }         LOC_SUBSETREG,         LOC_CSUBSETREG,         { contiguous subset of bits in memory }         LOC_SUBSETREF,         LOC_CSUBSETREF,         { keep these last for range checking purposes }         LOC_CREFERENCE,   { in memory constant value reference (cannot change) }         LOC_REFERENCE     { in memory value }       );       TCGNonRefLoc=low(TCGLoc)..pred(LOC_CREFERENCE);       TCGRefLoc=LOC_CREFERENCE..LOC_REFERENCE;       trefaddr = (         addr_no,         addr_full,         addr_pic,         addr_pic_no_got         {$IF defined(POWERPC) or defined(POWERPC64) or defined(SPARC) or defined(MIPS) or defined(SPARC64)}         ,         { since we have only 16bit offsets, we need to be able to specify the high           and lower 16 bits of the address of a symbol of up to 64 bit }         addr_low,         // bits 48-63         addr_high,        // bits 32-47         {$IF defined(POWERPC64)}         addr_higher,      // bits 16-31         addr_highest,     // bits 00-15         {$ENDIF}         addr_higha        // bits 16-31, adjusted         {$IF defined(POWERPC64)}         ,         addr_highera,     // bits 32-47, adjusted         addr_highesta     // bits 48-63, adjusted         {$ENDIF}         {$ENDIF POWERPC or POWERPC64 or SPARC or MIPS or SPARC64}         {$IFDEF MIPS}         ,         addr_pic_call16,  // like addr_pic, but generates call16 reloc instead of got16         addr_low_pic,     // for large GOT model, generate got_hi16 and got_lo16 relocs         addr_high_pic,         addr_low_call,    // counterpart of two above, generate call_hi16 and call_lo16 relocs         addr_high_call         {$ENDIF}         {$if defined(RISCV32) or defined(RISCV64)}         ,         addr_hi20,         addr_lo12,         addr_pcrel_hi20,         addr_pcrel_lo12,         addr_pcrel,         addr_got_pcrel_hi,         addr_plt         {$endif RISCV}         {$if defined(LOONGARCH64)}         ,         addr_b16, { %b16(sym) }         addr_b21, { %b21(sym) }         addr_b26, { %b26(sym) }         addr_pcrel, { Some times we only use sym like 'bxx rd,rj,sym'. And la.pcrel..sym }         addr_plt, { %plt(sym) }         addr_abs_hi20, { %abs_hi20(sym) }         addr_abs_lo12, { %abs_lo12(sym) }         addr_abs64_lo20, { %abs_lo20(sym) }         addr_abs64_hi12, { %abs_hi12(sym) }         addr_pc_hi20, { %pc_hi20(sym) }         addr_got_pc_hi20, { %got_pc_hi20(sym) }         addr_got_pc_lo12, { %got_pc_lo12(sym) }         addr_pc_lo12, { %pc_lo12(sym) }         addr_got, { la.got..sym }         addr_abs, { la.abs..sym }         addr_reg_reg, { use by [ld/st]x }         addr_reg_12i, { use by [ld/st] }         addr_reg_14i, { use by [ldptr/stptr] }         addr_reg { use by jr.. }         {$endif LOONGARCH64}         {$IFDEF AVR}         ,addr_lo8         ,addr_lo8_gs         ,addr_hi8         ,addr_hi8_gs         {$ENDIF}         {$IFDEF Z80}         ,addr_lo8         ,addr_hi8         {$ENDIF}         {$IFDEF i8086}         ,addr_dgroup      // the data segment group         ,addr_fardataseg  // the far data segment of the current pascal module (unit or program)         ,addr_seg         // used for getting the segment of an object, e.g. 'mov ax, SEG symbol'         {$ENDIF}         {$IFDEF AARCH64}         ,addr_page         ,addr_pageoffset         ,addr_gotpage         ,addr_gotpageoffset         {$ENDIF AARCH64}         {$ifdef SPARC64}         ,addr_gdop_hix22         ,addr_gdop_lox22         {$endif SPARC64}         {$IFDEF ARM}         ,addr_gottpoff         ,addr_tpoff         ,addr_tlsgd         ,addr_tlsdesc         ,addr_tlscall         {$ENDIF}         {$IFDEF i386}         ,addr_ntpoff         ,addr_tlsgd         {$ENDIF}{$ifdef x86_64}          ,addr_tpoff          ,addr_tlsgd{$endif x86_64}{$ifdef wasm32}          ,addr_got_tls{$endif wasm32}         );       {# Generic opcodes, which must be supported by all processors       }       topcg =       (          OP_NONE,          OP_MOVE,      { replaced operation with direct load }          OP_ADD,       { simple addition          }          OP_AND,       { simple logical and       }          OP_DIV,       { simple unsigned division }          OP_IDIV,      { simple signed division   }          OP_IMUL,      { simple signed multiply   }          OP_MUL,       { simple unsigned multiply }          OP_NEG,       { simple negate            }          OP_NOT,       { simple logical not       }          OP_OR,        { simple logical or        }          OP_SAR,       { arithmetic shift-right   }          OP_SHL,       { logical shift left       }          OP_SHR,       { logical shift right      }          OP_SUB,       { simple subtraction       }          OP_XOR,       { simple exclusive or      }          OP_ROL,       { rotate left              }          OP_ROR        { rotate right             }        );       {# Generic flag values - used for jump locations }       TOpCmp =       (          OC_NONE,          OC_EQ,           { equality comparison              }          OC_GT,           { greater than (signed)            }          OC_LT,           { less than (signed)               }          OC_GTE,          { greater or equal than (signed)   }          OC_LTE,          { less or equal than (signed)      }          OC_NE,           { not equal                        }          OC_BE,           { less or equal than (unsigned)    }          OC_B,            { less than (unsigned)             }          OC_AE,           { greater or equal than (unsigned) }          OC_A             { greater than (unsigned)          }        );       { indirect symbol flags }       tindsymflag = (is_data,is_weak);       tindsymflags = set of tindsymflag;       { OS_NO is also used memory references with large data that can         not be loaded in a register directly }       TCgSize = (OS_NO,                  OS_8,   OS_16,   OS_32,   OS_64,   OS_128,                  OS_S8,  OS_S16,  OS_S32,  OS_S64,  OS_S128,                 { single, double, extended, comp, float128 }                  OS_F32, OS_F64,  OS_F80,  OS_C64,  OS_F128,                 { multi-media sizes, describes only the register size but not how it is split,                   this information must be passed separately }                  OS_M8,  OS_M16,  OS_M32,  OS_M64,  OS_M128,  OS_M256,  OS_M512);      { Register types }      TRegisterType = (        R_INVALIDREGISTER, { = 0 }        R_INTREGISTER,     { = 1 }        R_FPUREGISTER,     { = 2 }        { used by Intel only }        R_MMXREGISTER,     { = 3 }        R_MMREGISTER,      { = 4 }        R_SPECIALREGISTER, { = 5 }        R_ADDRESSREGISTER, { = 6 }        { used on llvm, every temp gets its own "base register" }        R_TEMPREGISTER,    { = 7 }        { used on llvm for tracking metadata (every unique metadata has its own base register) }        R_METADATAREGISTER,{ = 8 }        { optional MAC16 (16 bit multiply-accumulate) registers on Xtensa }        R_MAC16REGISTER,   { = 9 }        { WebAssembly externref }        R_EXTERNREFREGISTER, { = 10 }        { WebAssembly funcref }        R_FUNCREFREGISTER  { = 11 }        { do not add more than 16 elements (ifdef by cpu type if needed)          so we can store this in one nibble and pack TRegister          if the supreg width should be extended }      );      { Sub registers }      TSubRegister = (        R_SUBNONE, { = 0; no sub register possible }        R_SUBL,    { = 1; 8 bits, Like AL }        R_SUBH,    { = 2; 8 bits, Like AH }        R_SUBW,    { = 3; 16 bits, Like AX }        R_SUBD,    { = 4; 32 bits, Like EAX }        R_SUBQ,    { = 5; 64 bits, Like RAX }        { For Sparc floats that use F0:F1 to store doubles }        R_SUBFS,   { = 6; Float that allocates 1 FPU register }        R_SUBFD,   { = 7; Float that allocates 2 FPU registers }        R_SUBFQ,   { = 8; Float that allocates 4 FPU registers }        R_SUBMMS,  { = 9; single scalar in multi media register }        R_SUBMMD,  { = 10; double scalar in multi media register }        R_SUBMMWHOLE,  { = 11; complete MM register, size depends on CPU }        { For Intel X86 AVX-Register }        R_SUBMMX,     { = 12; 128 BITS }        R_SUBMMY,     { = 13; 256 BITS }        R_SUBMMZ,     { = 14; 512 BITS }{$ifdef Z80}        { Subregisters for the flags register (Z80) }        R_SUBFLAGCARRY,          { = 15; Carry flag }        R_SUBFLAGADDSUBTRACT,    { = 16; Add/Subtract flag }        R_SUBFLAGPARITYOVERFLOW, { = 17; Parity/Overflow flag }        R_SUBFLAGUNUSEDBIT3,     { = 18; Unused flag (bit 3) }        R_SUBFLAGHALFCARRY,      { = 19; Half Carry flag }        R_SUBFLAGUNUSEDBIT5,     { = 20; Unused flag (bit 5) }        R_SUBFLAGZERO,           { = 21; Zero flag }        R_SUBFLAGSIGN,           { = 22; Sign flag }{$else Z80}        { Subregisters for the flags register (x86) }        R_SUBFLAGCARRY,     { = 15; Carry flag }        R_SUBFLAGPARITY,    { = 16; Parity flag }        R_SUBFLAGAUXILIARY, { = 17; Auxiliary flag }        R_SUBFLAGZERO,      { = 18; Zero flag }        R_SUBFLAGSIGN,      { = 19; Sign flag }        R_SUBFLAGOVERFLOW,  { = 20; Overflow flag }        R_SUBFLAGINTERRUPT, { = 21; Interrupt enable flag }        R_SUBFLAGDIRECTION, { = 22; Direction flag }{$endif Z80}        { subregisters for the metadata register (llvm) }        R_SUBMETASTRING    { = 23 }{$ifdef aarch64}        , R_SUBMM8B          { = 24; for arrangement of v regs on aarch64 }        , R_SUBMM16B         { = 25; for arrangement of v regs on aarch64 }        , R_SUBMM4H          { = 26; for arrangement of v regs on aarch64 }        , R_SUBMM8H          { = 27; for arrangement of v regs on aarch64 }        , R_SUBMM2S          { = 28; for arrangement of v regs on aarch64 }        , R_SUBMM4S          { = 29; for arrangement of v regs on aarch64 }        , R_SUBMM1D          { = 30; for arrangement of v regs on aarch64 }        , R_SUBMM2D          { = 31; for arrangement of v regs on aarch64 }        , R_SUBMMB1          { = 32; for arrangement of v regs on aarch64; for use with ldN/stN }        , R_SUBMMH1          { = 33; for arrangement of v regs on aarch64; for use with ldN/stN }        , R_SUBMMS1          { = 34; for arrangement of v regs on aarch64; for use with ldN/stN }        , R_SUBMMD1          { = 35; for arrangement of v regs on aarch64; for use with ldN/stN }{$endif aarch64}      );      TSubRegisterSet = set of TSubRegister;      TSuperRegister = type word;      {        The new register coding:        SuperRegister   (bits 0..15)        Subregister     (bits 16..23)        Register type   (bits 24..31)        TRegister is defined as an enum to make it incompatible        with TSuperRegister to avoid mixing them      }      TRegister = (        TRegisterLowEnum := Low(longint),        TRegisterHighEnum := High(longint)      );      TRegisterRec=packed record{$ifdef FPC_BIG_ENDIAN}         regtype : Tregistertype;         subreg  : Tsubregister;         supreg  : Tsuperregister;{$else FPC_BIG_ENDIAN}         supreg  : Tsuperregister;         subreg  : Tsubregister;         regtype : Tregistertype;{$endif FPC_BIG_ENDIAN}      end;      { A type to store register locations for 64 Bit values. }{$ifdef cpu64bitalu}      tregister64 = tregister;      tregister128 = record         reglo,reghi : tregister;      end;{$else cpu64bitalu}      tregister64 = record         reglo,reghi : tregister;      end;{$endif cpu64bitalu}      { Set type definition for registers }      tsuperregisterset = array[byte] of set of byte;      pmmshuffle = ^tmmshuffle;      { this record describes shuffle operations for mm operations; if a pointer a shuffle record        passed to an mm operation is nil, it means that the whole location is moved }      tmmshuffle = record        { describes how many shuffles are actually described, if len=0 then          moving the scalar with index 0 to the scalar with index 0 is meant,          if len=-1, then a variable/unknown length is assumed }        len : Shortint;        { lower byte of each entry of this array describes index of the source data index while          the upper byte describes the destination index }        shuffles : array[1..1] of word;      end;      Tsuperregisterarray=array[0..$ffff] of Tsuperregister;      Psuperregisterarray=^Tsuperregisterarray;      Tsuperregisterworklist=object        buflength,        buflengthinc,        length:word;        buf:Psuperregisterarray;        constructor init;        constructor copyfrom(const x:Tsuperregisterworklist);        destructor  done;        procedure clear;        procedure add(s:tsuperregister);        function addnodup(s:tsuperregister): boolean;        { returns the last element and removes it from the list }        function get:tsuperregister;        function readidx(i:word):tsuperregister;        procedure deleteidx(i:word);        function delete(s:tsuperregister):boolean;      end;      psuperregisterworklist=^tsuperregisterworklist;    const       { alias for easier understanding }       R_SSEREGISTER = R_MMREGISTER;       { Invalid register number }       RS_INVALID    = high(tsuperregister);       NR_INVALID    = tregister($ffffffff);       tcgsize2size : Array[tcgsize] of integer =        (0,         { integer values }         1,  2,  4,  8, 16,         1,  2,  4,  8, 16,         { floating point values }         4,  8, 10,  8, 16,         { multimedia values }         1,  2,  4,  8, 16, 32, 64);       tfloat2tcgsize: array[tfloattype] of tcgsize =         (OS_F32,OS_F64,OS_F80,OS_F80,OS_C64,OS_C64,OS_F128);       tcgsize2tfloat: array[OS_F32..OS_C64] of tfloattype =         (s32real,s64real,s80real,s64comp);       tvarregable2tcgloc : array[tvarregable] of tcgloc = (LOC_VOID,          LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMREGISTER,LOC_CREGISTER);{$if defined(cpu64bitalu)}       { operand size describing an unsigned value in a pair of int registers }       OS_PAIR = OS_128;       { operand size describing an signed value in a pair of int registers }       OS_SPAIR = OS_S128;{$elseif defined(cpu32bitalu)}       { operand size describing an unsigned value in a pair of int registers }       OS_PAIR = OS_64;       { operand size describing an signed value in a pair of int registers }       OS_SPAIR = OS_S64;{$elseif defined(cpu16bitalu)}       { operand size describing an unsigned value in a pair of int registers }       OS_PAIR = OS_32;       { operand size describing an signed value in a pair of int registers }       OS_SPAIR = OS_S32;{$elseif defined(cpu8bitalu)}       { operand size describing an unsigned value in a pair of int registers }       OS_PAIR = OS_16;       { operand size describing an signed value in a pair of int registers }       OS_SPAIR = OS_S16;{$endif}       { Table to convert tcgsize variables to the correspondending         unsigned types }       tcgsize2unsigned : array[tcgsize] of tcgsize = (OS_NO,         OS_8,    OS_16,   OS_32,   OS_64,   OS_128,         OS_8,    OS_16,   OS_32,   OS_64,   OS_128,         OS_F32,  OS_F64,  OS_F80,  OS_C64,  OS_F128,         OS_M8,   OS_M16,  OS_M32,  OS_M64,  OS_M128, OS_M256, OS_M512);       tcgsize2signed : array[tcgsize] of tcgsize = (OS_NO,         OS_S8,   OS_S16,  OS_S32,  OS_S64,  OS_S128,         OS_S8,   OS_S16,  OS_S32,  OS_S64,  OS_S128,         OS_F32,  OS_F64,  OS_F80,  OS_C64,  OS_F128,         OS_M8,   OS_M16,  OS_M32,  OS_M64,  OS_M128, OS_M256,OS_M512);       tcgloc2str : array[TCGLoc] of string[12] = (            'LOC_INVALID',            'LOC_VOID',            'LOC_CONST',            'LOC_JUMP',            'LOC_FLAGS',            'LOC_REG',            'LOC_CREG',            'LOC_FPUREG',            'LOC_CFPUREG',            'LOC_MMXREG',            'LOC_CMMXREG',            'LOC_MMREG',            'LOC_CMMREG',            'LOC_SSETREG',            'LOC_CSSETREG',            'LOC_SSETREF',            'LOC_CSSETREF',            'LOC_CREF',            'LOC_REF'            );    var       mms_movescalar,       mms_variable,       mms_2,       mms_4,       mms_8,       mms_16,       mms_32 : pmmshuffle;    procedure supregset_reset(out regs:tsuperregisterset;setall:boolean;                              maxreg:Tsuperregister);{$ifdef USEINLINE}inline;{$endif}    procedure supregset_include(var regs:tsuperregisterset;s:tsuperregister);{$ifdef USEINLINE}inline;{$endif}    procedure supregset_exclude(var regs:tsuperregisterset;s:tsuperregister);{$ifdef USEINLINE}inline;{$endif}    function supregset_in(const regs:tsuperregisterset;s:tsuperregister):boolean;{$ifdef USEINLINE}inline;{$endif}    function newreg(rt:tregistertype;sr:tsuperregister;sb:tsubregister):tregister;{$ifdef USEINLINE}inline;{$endif}    function getsubreg(r:tregister):tsubregister;{$ifdef USEINLINE}inline;{$endif}    function getsupreg(r:tregister):tsuperregister;{$ifdef USEINLINE}inline;{$endif}    function getregtype(r:tregister):tregistertype;{$ifdef USEINLINE}inline;{$endif}    procedure setsubreg(var r:tregister;sr:tsubregister);{$ifdef USEINLINE}inline;{$endif}    procedure setsupreg(var r:tregister;sr:tsuperregister);{$ifdef USEINLINE}inline;{$endif}    function generic_regname(r:tregister):string;    {# From a constant numeric value, return the abstract code generator       size.    }    function int_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}    function int_float_cgsize(const a: tcgint): tcgsize;    function float_array_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}    function double_array_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}    function tcgsize2str(cgsize: tcgsize):string;    { return the inverse condition of opcmp }    function inverse_opcmp(opcmp: topcmp): topcmp;{$ifdef USEINLINE}inline;{$endif}    { return the opcmp needed when swapping the operands }    function swap_opcmp(opcmp: topcmp): topcmp;{$ifdef USEINLINE}inline;{$endif}    { return whether op is commutative }    function commutativeop(op: topcg): boolean;{$ifdef USEINLINE}inline;{$endif}    { returns true, if shuffle describes a real shuffle operation and not only a move }    function realshuffle(shuffle : pmmshuffle) : boolean;    { returns true, if the shuffle describes only a move of the scalar at index 0 }    function shufflescalar(shuffle : pmmshuffle) : boolean;    { removes shuffling from shuffle, this means that the destenation index of each shuffle is copied to      the source }    procedure removeshuffles(var shuffle : tmmshuffle);    function is_float_cgsize(size: tcgsize): boolean;{$ifdef USEINLINE}inline;{$endif}implementation    uses      verbose,      cutils;{******************************************************************************                             tsuperregisterworklist******************************************************************************}    constructor tsuperregisterworklist.init;    begin      length:=0;      buflength:=0;      buflengthinc:=16;      buf:=nil;    end;    constructor Tsuperregisterworklist.copyfrom(const x:Tsuperregisterworklist);    begin      self:=x;      if x.buf<>nil then        begin          getmem(buf,buflength*sizeof(Tsuperregister));          move(x.buf^,buf^,length*sizeof(Tsuperregister));        end;    end;    destructor tsuperregisterworklist.done;    begin      if assigned(buf) then        freemem(buf);    end;    procedure tsuperregisterworklist.add(s:tsuperregister);    begin      inc(length);      { Need to increase buffer length? }      if length>=buflength then        begin          inc(buflength,buflengthinc);          buflengthinc:=buflengthinc*2;          if buflengthinc>256 then             buflengthinc:=256;          reallocmem(buf,buflength*sizeof(Tsuperregister));        end;      buf^[length-1]:=s;    end;    function tsuperregisterworklist.addnodup(s:tsuperregister): boolean;    begin      addnodup := false;      if indexword(buf^,length,s) = -1 then        begin          add(s);          addnodup := true;        end;    end;    procedure tsuperregisterworklist.clear;    begin      length:=0;    end;    procedure tsuperregisterworklist.deleteidx(i:word);    begin      if i>=length then        internalerror(200310144);      buf^[i]:=buf^[length-1];      dec(length);    end;    function tsuperregisterworklist.readidx(i:word):tsuperregister;      begin        if (i >= length) then          internalerror(2005010601);        result := buf^[i];      end;    function tsuperregisterworklist.get:tsuperregister;    begin      if length=0 then        internalerror(200310142);      dec(length);      get:=buf^[length];    end;    function tsuperregisterworklist.delete(s:tsuperregister):boolean;    var      i:longint;    begin      delete:=false;      { indexword in 1.0.x and 1.9.4 is broken }      i:=indexword(buf^,length,s);      if i<>-1 then        begin          deleteidx(i);          delete := true;        end;    end;    procedure supregset_reset(out regs:tsuperregisterset;setall:boolean;                              maxreg:Tsuperregister);{$ifdef USEINLINE}inline;{$endif}    begin      fillchar(regs,(maxreg+7) shr 3,-byte(setall));    end;    procedure supregset_include(var regs:tsuperregisterset;s:tsuperregister);{$ifdef USEINLINE}inline;{$endif}      begin        include(regs[s shr 8],(s and $ff));      end;    procedure supregset_exclude(var regs:tsuperregisterset;s:tsuperregister);{$ifdef USEINLINE}inline;{$endif}      begin        exclude(regs[s shr 8],(s and $ff));      end;    function supregset_in(const regs:tsuperregisterset;s:tsuperregister):boolean;{$ifdef USEINLINE}inline;{$endif}      begin        result:=(s and $ff) in regs[s shr 8];      end;    function newreg(rt:tregistertype;sr:tsuperregister;sb:tsubregister):tregister;{$ifdef USEINLINE}inline;{$endif}      begin        tregisterrec(result).regtype:=rt;        tregisterrec(result).supreg:=sr;        tregisterrec(result).subreg:=sb;      end;    function getsubreg(r:tregister):tsubregister;{$ifdef USEINLINE}inline;{$endif}      begin        result:=tregisterrec(r).subreg;      end;    function getsupreg(r:tregister):tsuperregister;{$ifdef USEINLINE}inline;{$endif}      begin        result:=tregisterrec(r).supreg;      end;    function getregtype(r:tregister):tregistertype;{$ifdef USEINLINE}inline;{$endif}      begin        result:=tregisterrec(r).regtype;      end;    procedure setsubreg(var r:tregister;sr:tsubregister);{$ifdef USEINLINE}inline;{$endif}      begin        tregisterrec(r).subreg:=sr;      end;    procedure setsupreg(var r:tregister;sr:tsuperregister);{$ifdef USEINLINE}inline;{$endif}      begin        tregisterrec(r).supreg:=sr;      end;    function generic_regname(r:tregister):string;      var        nr : string[12];      begin        str(getsupreg(r),nr);        case getregtype(r) of          R_INTREGISTER:            result:='ireg'+nr;          R_FPUREGISTER:            result:='freg'+nr;          R_MMREGISTER:            result:='mreg'+nr;          R_MMXREGISTER:            result:='xreg'+nr;          R_ADDRESSREGISTER:            result:='areg'+nr;          R_SPECIALREGISTER:            result:='sreg'+nr;          else            begin              result:='INVALID';              exit;            end;        end;        case getsubreg(r) of          R_SUBNONE:            ;          R_SUBL:            result:=result+'l';          R_SUBH:            result:=result+'h';          R_SUBW:            result:=result+'w';          R_SUBD:            result:=result+'d';          R_SUBQ:            result:=result+'q';          R_SUBFS:            result:=result+'fs';          R_SUBFD:            result:=result+'fd';          R_SUBMMD:            result:=result+'md';          R_SUBMMS:            result:=result+'ms';          R_SUBMMWHOLE:            result:=result+'ma';          R_SUBMMX:            result:=result+'mx';          R_SUBMMY:            result:=result+'my';          R_SUBMMZ:            result:=result+'mz';{$ifdef aarch64}          R_SUBMM8B:            result:=result+'m8b';          R_SUBMM16B:            result:=result+'m16b';          R_SUBMM4H:            result:=result+'m4h';          R_SUBMM8H:            result:=result+'m8h';          R_SUBMM2S:            result:=result+'m2s';          R_SUBMM4S:            result:=result+'m4s';          R_SUBMM2D:            result:=result+'m2d';          R_SUBMMB1:            result:=result+'mb1';          R_SUBMMH1:            result:=result+'mh1';          R_SUBMMS1:            result:=result+'ms1';          R_SUBMMD1:            result:=result+'md1';{$endif}          else            internalerror(200308252);        end;      end;    function int_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}      const        size2cgsize : array[0..8] of tcgsize = (          OS_NO,OS_8,OS_16,OS_NO,OS_32,OS_NO,OS_NO,OS_NO,OS_64        );      begin{$ifdef cpu64bitalu}        if a=16 then          result:=OS_128        else{$endif cpu64bitalu}        if a>8 then          result:=OS_NO        else          result:=size2cgsize[a];      end;    function int_float_cgsize(const a: tcgint): tcgsize;      begin        case a of          4 :            result:=OS_F32;          8 :            result:=OS_F64;          10 :            result:=OS_F80;          16 :            result:=OS_F128;          else            internalerror(200603211);        end;      end;    function float_array_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}      begin        case a of          4:            result := OS_M32;          16:            result := OS_M128;          32:            result := OS_M256;          64:            result := OS_M512;          else            result := int_cgsize(a);        end;      end;    function double_array_cgsize(const a: tcgint): tcgsize;{$ifdef USEINLINE}inline;{$endif}      begin        case a of          8:            result := OS_M64;          16:            result := OS_M128;          32:            result := OS_M256;          64:            result := OS_M512;          else            result := int_cgsize(a);        end;      end;    function tcgsize2str(cgsize: tcgsize):string;      begin        Str(cgsize, Result);      end;    function inverse_opcmp(opcmp: topcmp): topcmp;{$ifdef USEINLINE}inline;{$endif}      const        list: array[TOpCmp] of TOpCmp =          (OC_NONE,OC_NE,OC_LTE,OC_GTE,OC_LT,OC_GT,OC_EQ,OC_A,OC_AE,           OC_B,OC_BE);      begin        inverse_opcmp := list[opcmp];      end;    function swap_opcmp(opcmp: topcmp): topcmp;{$ifdef USEINLINE}inline;{$endif}      const        list: array[TOpCmp] of TOpCmp =          (OC_NONE,OC_EQ,OC_LT,OC_GT,OC_LTE,OC_GTE,OC_NE,OC_AE,OC_A,           OC_BE,OC_B);      begin        swap_opcmp := list[opcmp];      end;    function commutativeop(op: topcg): boolean;{$ifdef USEINLINE}inline;{$endif}      const        list: array[topcg] of boolean =          (true,false,true,true,false,false,true,true,false,false,           true,false,false,false,false,true,false,false);      begin        commutativeop := list[op];      end;    function realshuffle(shuffle : pmmshuffle) : boolean;      var        i : longint;      begin        realshuffle:=true;        if (shuffle=nil) or (shuffle^.len<1) then          realshuffle:=false        else          begin            for i:=1 to shuffle^.len do              begin                if (shuffle^.shuffles[i] and $ff)<>((shuffle^.shuffles[i] and $ff00) shr 8) then                  exit;              end;            realshuffle:=false;          end;      end;    function shufflescalar(shuffle : pmmshuffle) : boolean;      begin        result:=shuffle^.len=0;      end;    procedure removeshuffles(var shuffle : tmmshuffle);      var        i : longint;      begin        if shuffle.len=0 then          exit;        for i:=1 to shuffle.len do          shuffle.shuffles[i]:=(shuffle.shuffles[i] and $f) or ((shuffle.shuffles[i] and $f0) shr 4);      end;    function is_float_cgsize(size: tcgsize): boolean;{$ifdef USEINLINE}inline;{$endif}      begin        result:=size in [OS_F32..OS_F128];      end;   procedure Initmms(var p : pmmshuffle;len : ShortInt);     var       i : Integer;     begin       Getmem(p,sizeof(tmmshuffle)+(max(len,0)-1)*2);       p^.len:=len;       for i:=1 to len do{$push}{$R-}         p^.shuffles[i]:=i;{$pop}     end;initialization  Initmms(mms_movescalar,0);  Initmms(mms_variable,-1);  Initmms(mms_2,2);  Initmms(mms_4,4);  Initmms(mms_8,8);  Initmms(mms_16,16);  Initmms(mms_32,32);finalization  Freemem(mms_movescalar);  Freemem(mms_variable);  Freemem(mms_2);  Freemem(mms_4);  Freemem(mms_8);  Freemem(mms_16);  Freemem(mms_32);end.
 |