瀏覽代碼

* fixed more problems with cpubase and x86-64

florian 23 年之前
父節點
當前提交
37194d2f61
共有 6 個文件被更改,包括 5520 次插入0 次删除
  1. 1955 0
      compiler/aasmtai.pas
  2. 211 0
      compiler/i386/cpubase.inc
  3. 2109 0
      compiler/x86/aasmcpu.pas
  4. 911 0
      compiler/x86/cpubase.pas
  5. 187 0
      compiler/x86_64/cpubase.inc
  6. 147 0
      compiler/x86_64/cpupara.pas

+ 1955 - 0
compiler/aasmtai.pas

@@ -0,0 +1,1955 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements an abstract asmoutput class for all processor types
+
+    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.
+
+ ****************************************************************************
+}
+{ @abstract(This unit implements an abstract asm output class for all processor types)
+  This unit implements an abstract assembler output class for all processors, these
+  are then overriden for each assembler writer to actually write the data in these
+  classes to an assembler file.
+}
+
+unit aasmtai;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       cutils,cclasses,
+       globtype,globals,systems,
+       cpuinfo,cpubase,
+       symppu,
+       aasmbase;
+
+    type
+       taitype = (
+          ait_none,
+          ait_align,
+          ait_section,
+          ait_comment,
+          ait_direct,
+          ait_string,
+          ait_instruction,
+          ait_datablock,
+          ait_symbol,
+          ait_symbol_end, { needed to calc the size of a symbol }
+          ait_label,
+          ait_const_32bit,
+          ait_const_16bit,
+          ait_const_8bit,
+          ait_const_symbol,
+          { the following is only used by the win32 version of the compiler }
+          { and only the GNU AS Win32 is able to write it                   }
+          ait_const_rva,
+          ait_real_32bit,
+          ait_real_64bit,
+          ait_real_80bit,
+          ait_comp_64bit,
+          ait_real_128bit,
+{$ifdef GDB}
+          ait_stabn,
+          ait_stabs,
+          ait_force_line,
+          ait_stab_function_name,
+{$endif GDB}
+{$ifdef alpha}
+          { the follow is for the DEC Alpha }
+          ait_frame,
+          ait_ent,
+{$endif alpha}
+{$ifdef ia64}
+          ait_bundle,
+          ait_stop,
+{$endif ia64}
+{$ifdef m68k}
+          ait_labeled_instruction,
+{$endif m68k}
+{$ifdef SPARC}
+          ait_labeled_instruction,
+{$endif SPARC}
+          ait_cut, { used to split into tiny assembler files }
+          ait_regalloc,
+          ait_tempalloc,
+          ait_marker { used to mark assembler blocks and inlined functions }
+          );
+
+    const
+       taitypestr : array[taitype] of string[14] = (
+          '<none>',
+          'align',
+          'section',
+          'comment',
+          'direct',
+          'string',
+          'instruction',
+          'datablock',
+          'symbol',
+          'symbol_end',
+          'label',
+          'const_32bit',
+          'const_16bit',
+          'const_8bit',
+          'const_symbol',
+          'const_rva',
+          'real_32bit',
+          'real_64bit',
+          'real_80bit',
+          'comp_64bit',
+          'real_128bit',
+{$ifdef GDB}
+          'stabn',
+          'stabs',
+          'force_line',
+          'stab_funcname',
+{$endif GDB}
+{$ifdef alpha}
+          { the follow is for the DEC Alpha }
+          'frame',
+          'ent',
+{$endif alpha}
+{$ifdef ia64}
+          'bundle',
+          'stop',
+{$endif ia64}
+{$ifdef m68k}
+          'labeled_instr',
+{$endif m68k}
+{$ifdef SPARC}
+          'labeled_instr',
+{$endif SPARC}
+          'cut',
+          'regalloc',
+          'tempalloc',
+          'marker'
+          );
+
+{ ait_* types which don't result in executable code or which don't influence   }
+{ the way the program runs/behaves, but which may be encountered by the        }
+{ optimizer (= if it's sometimes added to the exprasm list). Update if you add }
+{ a new ait type!                                                              }
+    const
+      SkipInstr = [ait_comment, ait_symbol,ait_section
+{$ifdef GDB}
+                   ,ait_stabs, ait_stabn, ait_stab_function_name, ait_force_line
+{$endif GDB}
+                   ,ait_regalloc, ait_tempalloc, ait_symbol_end];
+
+{ ait_* types which do not have line information (and hence which are of type
+  tai, otherwise, they are of type tailineinfo }
+{ ait_* types which do not have line information (and hence which are of type
+  tai, otherwise, they are of type tailineinfo }
+      SkipLineInfo =[ait_label,
+                     ait_regalloc,ait_tempalloc,
+{$ifdef GDB}
+                  ait_stabn,ait_stabs,ait_stab_function_name,
+{$endif GDB}
+                  ait_cut,ait_marker,ait_align,ait_section,ait_comment,
+                  ait_const_8bit,ait_const_16bit,ait_const_32bit,
+                  ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit
+                  ];
+
+
+    type
+       { cut type, required for alphanumeric ordering of the assembler filenames }
+       TCutPlace=(cut_normal,cut_begin,cut_end);
+
+       TMarker = (NoPropInfoStart,NoPropInfoEnd,
+                  AsmBlockStart,AsmBlockEnd,
+                  InlineStart,InlineEnd);
+
+       { Buffer type used for alignment }
+       tfillbuffer = array[0..63] of char;
+
+       { abstract assembler item }
+       tai = class(TLinkedListItem)
+{$ifndef NOOPT}
+          { pointer to record with optimizer info about this tai object }
+          optinfo  : pointer;
+{$endif NOOPT}
+          typ      : taitype;
+          constructor Create;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);virtual;
+          procedure ppuwrite(ppufile:tcompilerppufile);virtual;
+          procedure derefimpl;virtual;
+          { helper for checking symbol redefines }
+          procedure checkredefinesym(sym:tasmsymbol);
+       end;
+
+       { abstract assembler item with line information }
+       tailineinfo = class(tai)
+        fileinfo : tfileposinfo;
+        constructor Create;
+        constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+        procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+
+       taiclass = class of tai;
+
+       taiclassarray = array[taitype] of taiclass;
+
+       { Generates an assembler string }
+       tai_string = class(tailineinfo)
+          str : pchar;
+          { extra len so the string can contain an \0 }
+          len : longint;
+          constructor Create(const _str : string);
+          constructor Create_pchar(_str : pchar);
+          constructor Create_length_pchar(_str : pchar;length : longint);
+          destructor Destroy;override;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          function getcopy:tlinkedlistitem;override;
+       end;
+
+       { Generates a common label }
+       tai_symbol = class(tailineinfo)
+          is_global : boolean;
+          sym       : tasmsymbol;
+          size      : longint;
+          constructor Create(_sym:tasmsymbol;siz:longint);
+          constructor Createname(const _name : string;siz:longint);
+          constructor Createname_global(const _name : string;siz:longint);
+          constructor Createdataname(const _name : string;siz:longint);
+          constructor Createdataname_global(const _name : string;siz:longint);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+       end;
+
+       tai_symbol_end = class(tailineinfo)
+          sym : tasmsymbol;
+          constructor Create(_sym:tasmsymbol);
+          constructor Createname(const _name : string);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+       end;
+
+       { Generates an assembler label }
+       tai_label = class(tai)
+          is_global : boolean;
+          l         : tasmlabel;
+          constructor Create(_l : tasmlabel);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+       end;
+
+       { Directly output data to final assembler file }
+       tai_direct = class(tailineinfo)
+          str : pchar;
+          constructor Create(_str : pchar);
+          destructor Destroy; override;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          function getcopy:tlinkedlistitem;override;
+       end;
+
+       { Generates an assembler comment }
+       tai_comment = class(tai)
+          str : pchar;
+          constructor Create(_str : pchar);
+          destructor Destroy; override;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          function getcopy:tlinkedlistitem;override;
+       end;
+
+
+       { Generates a section / segment directive }
+       tai_section = class(tai)
+          sec : TSection;
+          constructor Create(s : TSection);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+
+       { Generates an uninitializised data block }
+       tai_datablock = class(tailineinfo)
+          is_global : boolean;
+          sym       : tasmsymbol;
+          size      : longint;
+          constructor Create(const _name : string;_size : longint);
+          constructor Create_global(const _name : string;_size : longint);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+       end;
+
+
+       { Generates a long integer (32 bit) }
+       tai_const = class(tai)
+          value : longint;
+          constructor Create_32bit(_value : longint);
+          constructor Create_16bit(_value : word);
+          constructor Create_8bit(_value : byte);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       tai_const_symbol = class(tailineinfo)
+          sym    : tasmsymbol;
+          offset : longint;
+          constructor Create(_sym:tasmsymbol);
+          constructor Create_offset(_sym:tasmsymbol;ofs:longint);
+          constructor Create_rva(_sym:tasmsymbol);
+          constructor Createname(const name:string);
+          constructor Createname_offset(const name:string;ofs:longint);
+          constructor Createname_rva(const name:string);
+          constructor Createdataname(const name:string);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+          function getcopy:tlinkedlistitem;override;
+       end;
+
+       { Generates a single float (32 bit real) }
+       tai_real_32bit = class(tai)
+          value : ts32real;
+          constructor Create(_value : ts32real);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Generates a double float (64 bit real) }
+       tai_real_64bit = class(tai)
+          value : ts64real;
+          constructor Create(_value : ts64real);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Generates an extended float (80 bit real) }
+       tai_real_80bit = class(tai)
+          value : ts80real;
+          constructor Create(_value : ts80real);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Generates a comp int (integer over 64 bits)
+
+          This is Intel 80x86 specific, and is not
+          really supported on other processors.
+       }
+       tai_comp_64bit = class(tai)
+          value : ts64comp;
+          constructor Create(_value : ts64comp);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Insert a cut to split assembler into several smaller files }
+       tai_cut = class(tai)
+          place : tcutplace;
+          constructor Create;
+          constructor Create_begin;
+          constructor Create_end;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Insert a marker for assembler and inline blocks }
+       tai_marker = class(tai)
+          Kind: TMarker;
+          Constructor Create(_Kind: TMarker);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       tai_tempalloc = class(tai)
+          allocation : boolean;
+{$ifdef EXTDEBUG}
+          problem : pstring;
+{$endif EXTDEBUG}
+          temppos,
+          tempsize   : longint;
+          constructor alloc(pos,size:longint);
+          constructor dealloc(pos,size:longint);
+{$ifdef EXTDEBUG}
+          constructor allocinfo(pos,size:longint;const st:string);
+{$endif EXTDEBUG}
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       tai_regalloc = class(tai)
+          allocation : boolean;
+          reg        : tregister;
+          constructor alloc(r : tregister);
+          constructor dealloc(r : tregister);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+       end;
+
+       { Class template for assembler instructions
+       }
+       taicpu_abstract = class(tailineinfo)
+       protected
+          procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);virtual;abstract;
+          procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);virtual;abstract;
+          procedure ppuderefoper(var o:toper);virtual;abstract;
+       public
+          { Condition flags for instruction }
+          condition : TAsmCond;
+          { Number of operands to instruction }
+          ops       : byte;
+          { Operands of instruction }
+          oper      : array[0..max_operands-1] of toper;
+          { Actual opcode of instruction }
+          opcode    : tasmop;
+{$ifdef x86}
+          segprefix : tregister;
+{$endif x86}
+          { true if instruction is a jmp }
+          is_jmp    : boolean; { is this instruction a jump? (needed for optimizer) }
+          Constructor Create(op : tasmop);
+          Destructor Destroy;override;
+          function getcopy:TLinkedListItem;override;
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure derefimpl;override;
+          procedure SetCondition(const c:TAsmCond);
+          procedure loadconst(opidx:longint;l:aword);
+          procedure loadsymbol(opidx:longint;s:tasmsymbol;sofs:longint);
+          procedure loadref(opidx:longint;const r:treference);
+          procedure loadreg(opidx:longint;r:tregister);
+          procedure loadoper(opidx:longint;o:toper);
+          function is_nop:boolean;virtual;abstract;
+       end;
+
+       { alignment for operator }
+       tai_align_abstract = class(tai)
+          aligntype : byte;   { 1 = no align, 2 = word align, 4 = dword align }
+          fillsize  : byte;   { real size to fill }
+          fillop    : byte;   { value to fill with - optional }
+          use_op    : boolean;
+          constructor Create(b:byte);
+          constructor Create_op(b: byte; _op: byte);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          function calculatefillbuf(var buf : tfillbuffer):pchar;virtual;
+       end;
+
+       Ttranstable=array[Tsuperregister] of Tsuperregister;
+
+       taasmoutput = class(tlinkedlist)
+          function getlasttaifilepos : pfileposinfo;
+          procedure convert_registers;
+          procedure translate_registers(const table:Ttranstable);
+       end;
+
+
+    var
+      { array with all class types for tais }
+      aiclass : taiclassarray;
+      { temporary lists }
+      exprasmlist,
+      { default lists }
+      datasegment,codesegment,bsssegment,
+      debuglist,withdebuglist,consts,
+      importssection,exportssection,
+      resourcesection,rttilist,
+      resourcestringlist         : taasmoutput;
+
+
+    function ppuloadai(ppufile:tcompilerppufile):tai;
+    procedure ppuwriteai(ppufile:tcompilerppufile;n:tai);
+
+
+implementation
+
+uses
+{$ifdef delphi}
+  sysutils,
+{$else}
+  strings,
+{$endif}
+  verbose;
+
+    const
+      pputaimarker = 254;
+
+
+{****************************************************************************
+                                 Helpers
+ ****************************************************************************}
+
+    function ppuloadai(ppufile:tcompilerppufile):tai;
+      var
+        b : byte;
+        t : taitype;
+      begin
+        { marker }
+        b:=ppufile.getbyte;
+        if b<>pputaimarker then
+          internalerror(200208181);
+        { load nodetype }
+        t:=taitype(ppufile.getbyte);
+        if t<>ait_none then
+         begin
+           if t>high(taitype) then
+             internalerror(200208182);
+           if not assigned(aiclass[t]) then
+             internalerror(200208183);
+           //writeln('taiload: ',taitypestr[t]);
+           { generate tai of the correct class }
+           ppuloadai:=aiclass[t].ppuload(t,ppufile);
+         end
+        else
+         ppuloadai:=nil;
+      end;
+
+
+    procedure ppuwriteai(ppufile:tcompilerppufile;n:tai);
+      begin
+        { marker, read by ppuloadnode }
+        ppufile.putbyte(pputaimarker);
+        if assigned(n) then
+         begin
+           { type, read by ppuloadnode }
+           ppufile.putbyte(byte(n.typ));
+           //writeln('taiwrite: ',taitypestr[n.typ]);
+           n.ppuwrite(ppufile);
+         end
+        else
+         ppufile.putbyte(byte(ait_none));
+      end;
+
+
+{****************************************************************************
+                             TAI
+ ****************************************************************************}
+
+    constructor tai.Create;
+      begin
+{$ifndef NOOPT}
+        optinfo:=nil;
+{$endif NOOPT}
+      end;
+
+
+    constructor tai.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        typ:=t;
+{$ifndef NOOPT}
+        optinfo:=nil;
+{$endif}
+      end;
+
+
+    procedure tai.ppuwrite(ppufile:tcompilerppufile);
+      begin
+      end;
+
+
+    procedure tai.derefimpl;
+      begin
+      end;
+
+
+    procedure tai.checkredefinesym(sym:tasmsymbol);
+      begin
+{        if assigned(sym.taiowner) and
+            (target_asm.id in binassem) then
+         begin
+           Message1(asmw_e_redefined_label,sym.name);
+         end
+        else
+         sym.taiowner:=self;}
+      end;
+
+
+{****************************************************************************
+                              TAILINEINFO
+ ****************************************************************************}
+
+    constructor tailineinfo.create;
+     begin
+       inherited create;
+       fileinfo:=aktfilepos;
+     end;
+
+
+    constructor tailineinfo.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        ppufile.getposinfo(fileinfo);
+      end;
+
+
+    procedure tailineinfo.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putposinfo(fileinfo);
+      end;
+
+
+{****************************************************************************
+                             TAI_SECTION
+ ****************************************************************************}
+
+    constructor tai_section.Create(s : TSection);
+      begin
+         inherited Create;
+         typ:=ait_section;
+         sec:=s;
+      end;
+
+
+    constructor tai_section.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        sec:=tsection(ppufile.getbyte);
+      end;
+
+
+    procedure tai_section.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putbyte(byte(sec));
+      end;
+
+
+{****************************************************************************
+                             TAI_DATABLOCK
+ ****************************************************************************}
+
+    constructor tai_datablock.Create(const _name : string;_size : longint);
+
+      begin
+         inherited Create;
+         typ:=ait_datablock;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_LOCAL,AT_DATA);
+{         checkredefinesym(sym);}
+         { keep things aligned }
+         if _size<=0 then
+           _size:=4;
+         size:=_size;
+         is_global:=false;
+      end;
+
+
+    constructor tai_datablock.Create_global(const _name : string;_size : longint);
+      begin
+         inherited Create;
+         typ:=ait_datablock;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_GLOBAL,AT_DATA);
+{         checkredefinesym(sym);}
+         { keep things aligned }
+         if _size<=0 then
+           _size:=4;
+         size:=_size;
+         is_global:=true;
+      end;
+
+
+    constructor tai_datablock.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited Create;
+        sym:=ppufile.getasmsymbol;
+        size:=ppufile.getlongint;
+        is_global:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure tai_datablock.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putasmsymbol(sym);
+        ppufile.putlongint(size);
+        ppufile.putbyte(byte(is_global));
+      end;
+
+
+    procedure tai_datablock.derefimpl;
+      begin
+        objectlibrary.DerefAsmsymbol(sym);
+      end;
+
+
+{****************************************************************************
+                               TAI_SYMBOL
+ ****************************************************************************}
+
+    constructor tai_symbol.Create(_sym:tasmsymbol;siz:longint);
+      begin
+         inherited Create;
+         typ:=ait_symbol;
+         sym:=_sym;
+{         checkredefinesym(sym);}
+         size:=siz;
+         is_global:=(sym.defbind=AB_GLOBAL);
+      end;
+
+    constructor tai_symbol.Createname(const _name : string;siz:longint);
+      begin
+         inherited Create;
+         typ:=ait_symbol;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_LOCAL,AT_FUNCTION);
+{         checkredefinesym(sym);}
+         size:=siz;
+         is_global:=false;
+      end;
+
+    constructor tai_symbol.Createname_global(const _name : string;siz:longint);
+      begin
+         inherited Create;
+         typ:=ait_symbol;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_GLOBAL,AT_FUNCTION);
+{         checkredefinesym(sym);}
+         size:=siz;
+         is_global:=true;
+      end;
+
+    constructor tai_symbol.Createdataname(const _name : string;siz:longint);
+      begin
+         inherited Create;
+         typ:=ait_symbol;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_LOCAL,AT_DATA);
+{         checkredefinesym(sym);}
+         size:=siz;
+         is_global:=false;
+      end;
+
+    constructor tai_symbol.Createdataname_global(const _name : string;siz:longint);
+      begin
+         inherited Create;
+         typ:=ait_symbol;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_GLOBAL,AT_DATA);
+{         checkredefinesym(sym);}
+         size:=siz;
+         is_global:=true;
+      end;
+
+
+    constructor tai_symbol.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        sym:=ppufile.getasmsymbol;
+        size:=ppufile.getlongint;
+        is_global:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure tai_symbol.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putasmsymbol(sym);
+        ppufile.putlongint(size);
+        ppufile.putbyte(byte(is_global));
+      end;
+
+
+    procedure tai_symbol.derefimpl;
+      begin
+        objectlibrary.DerefAsmsymbol(sym);
+      end;
+
+
+{****************************************************************************
+                               TAI_SYMBOL
+ ****************************************************************************}
+
+    constructor tai_symbol_end.Create(_sym:tasmsymbol);
+      begin
+         inherited Create;
+         typ:=ait_symbol_end;
+         sym:=_sym;
+      end;
+
+    constructor tai_symbol_end.Createname(const _name : string);
+      begin
+         inherited Create;
+         typ:=ait_symbol_end;
+         sym:=objectlibrary.newasmsymboltype(_name,AB_GLOBAL,AT_NONE);
+      end;
+
+    constructor tai_symbol_end.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        sym:=ppufile.getasmsymbol;
+      end;
+
+
+    procedure tai_symbol_end.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putasmsymbol(sym);
+      end;
+
+
+    procedure tai_symbol_end.derefimpl;
+      begin
+        objectlibrary.DerefAsmsymbol(sym);
+      end;
+
+
+{****************************************************************************
+                               TAI_CONST
+ ****************************************************************************}
+
+    constructor tai_const.Create_32bit(_value : longint);
+
+      begin
+         inherited Create;
+         typ:=ait_const_32bit;
+         value:=_value;
+      end;
+
+    constructor tai_const.Create_16bit(_value : word);
+
+      begin
+         inherited Create;
+         typ:=ait_const_16bit;
+         value:=_value;
+      end;
+
+    constructor tai_const.Create_8bit(_value : byte);
+
+      begin
+         inherited Create;
+         typ:=ait_const_8bit;
+         value:=_value;
+      end;
+
+
+    constructor tai_const.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        value:=ppufile.getlongint;
+      end;
+
+
+    procedure tai_const.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putlongint(value);
+      end;
+
+
+{****************************************************************************
+                               TAI_CONST_SYMBOL
+ ****************************************************************************}
+
+    constructor tai_const_symbol.Create(_sym:tasmsymbol);
+      begin
+         inherited Create;
+         typ:=ait_const_symbol;
+         sym:=_sym;
+         offset:=0;
+         { update sym info }
+         sym.increfs;
+      end;
+
+    constructor tai_const_symbol.Create_offset(_sym:tasmsymbol;ofs:longint);
+      begin
+         inherited Create;
+         typ:=ait_const_symbol;
+         sym:=_sym;
+         offset:=ofs;
+         { update sym info }
+         sym.increfs;
+      end;
+
+    constructor tai_const_symbol.Create_rva(_sym:tasmsymbol);
+      begin
+         inherited Create;
+         typ:=ait_const_rva;
+         sym:=_sym;
+         offset:=0;
+         { update sym info }
+         sym.increfs;
+      end;
+
+    constructor tai_const_symbol.Createname(const name:string);
+      begin
+         inherited Create;
+         typ:=ait_const_symbol;
+         sym:=objectlibrary.newasmsymbol(name);
+         offset:=0;
+         { update sym info }
+         sym.increfs;
+      end;
+
+    constructor tai_const_symbol.Createname_offset(const name:string;ofs:longint);
+      begin
+         inherited Create;
+         typ:=ait_const_symbol;
+         sym:=objectlibrary.newasmsymbol(name);
+         offset:=ofs;
+         { update sym info }
+         sym.increfs;
+      end;
+
+    constructor tai_const_symbol.Createname_rva(const name:string);
+      begin
+         inherited Create;
+         typ:=ait_const_rva;
+         sym:=objectlibrary.newasmsymbol(name);
+         offset:=0;
+         { update sym info }
+         sym.increfs;
+      end;
+
+
+    constructor tai_const_symbol.Createdataname(const name:string);
+      begin
+         inherited Create;
+         typ:=ait_const_symbol;
+         sym:=objectlibrary.newasmsymboltype(name,AB_EXTERNAL,AT_DATA);
+         offset:=0;
+         { update sym info }
+         sym.increfs;
+      end;
+
+
+    constructor tai_const_symbol.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        sym:=ppufile.getasmsymbol;
+        offset:=ppufile.getlongint;
+      end;
+
+
+    procedure tai_const_symbol.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putasmsymbol(sym);
+        ppufile.putlongint(offset);
+      end;
+
+
+    procedure tai_const_symbol.derefimpl;
+      begin
+        objectlibrary.DerefAsmsymbol(sym);
+      end;
+
+
+    function tai_const_symbol.getcopy:tlinkedlistitem;
+      begin
+        getcopy:=inherited getcopy;
+        { we need to increase the reference number }
+        sym.increfs;
+      end;
+
+
+{****************************************************************************
+                               TAI_real_32bit
+ ****************************************************************************}
+
+    constructor tai_real_32bit.Create(_value : ts32real);
+
+      begin
+         inherited Create;
+         typ:=ait_real_32bit;
+         value:=_value;
+      end;
+
+    constructor tai_real_32bit.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        value:=ppufile.getreal;
+      end;
+
+
+    procedure tai_real_32bit.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putreal(value);
+      end;
+
+
+{****************************************************************************
+                               TAI_real_64bit
+ ****************************************************************************}
+
+    constructor tai_real_64bit.Create(_value : ts64real);
+
+      begin
+         inherited Create;
+         typ:=ait_real_64bit;
+         value:=_value;
+      end;
+
+
+    constructor tai_real_64bit.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        value:=ppufile.getreal;
+      end;
+
+
+    procedure tai_real_64bit.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putreal(value);
+      end;
+
+
+{****************************************************************************
+                               TAI_real_80bit
+ ****************************************************************************}
+
+    constructor tai_real_80bit.Create(_value : ts80real);
+
+      begin
+         inherited Create;
+         typ:=ait_real_80bit;
+         value:=_value;
+      end;
+
+
+    constructor tai_real_80bit.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        value:=ppufile.getreal;
+      end;
+
+
+    procedure tai_real_80bit.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putreal(value);
+      end;
+
+
+{****************************************************************************
+                               Tai_comp_64bit
+ ****************************************************************************}
+
+    constructor tai_comp_64bit.Create(_value : ts64comp);
+
+      begin
+         inherited Create;
+         typ:=ait_comp_64bit;
+         value:=_value;
+      end;
+
+
+    constructor tai_comp_64bit.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        ppufile.putdata(value,sizeof(value));
+      end;
+
+
+    procedure tai_comp_64bit.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.getdata(value,sizeof(value));
+      end;
+
+
+{****************************************************************************
+                               TAI_STRING
+ ****************************************************************************}
+
+     constructor tai_string.Create(const _str : string);
+
+       begin
+          inherited Create;
+          typ:=ait_string;
+          len:=length(_str);
+          getmem(str,len+1);
+          strpcopy(str,_str);
+       end;
+
+     constructor tai_string.Create_pchar(_str : pchar);
+
+       begin
+          inherited Create;
+          typ:=ait_string;
+          str:=_str;
+          len:=strlen(_str);
+       end;
+
+    constructor tai_string.Create_length_pchar(_str : pchar;length : longint);
+
+       begin
+          inherited Create;
+          typ:=ait_string;
+          str:=_str;
+          len:=length;
+       end;
+
+    destructor tai_string.destroy;
+
+      begin
+         { you can have #0 inside the strings so }
+         if str<>nil then
+           freemem(str,len+1);
+         inherited Destroy;
+      end;
+
+
+    constructor tai_string.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        len:=ppufile.getlongint;
+        getmem(str,len+1);
+        ppufile.getdata(str^,len);
+        str[len]:=#0;
+      end;
+
+
+    procedure tai_string.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putlongint(len);
+        ppufile.putdata(str^,len);
+      end;
+
+
+    function tai_string.getcopy : tlinkedlistitem;
+      var
+        p : tlinkedlistitem;
+      begin
+        p:=inherited getcopy;
+        getmem(tai_string(p).str,len+1);
+        move(str^,tai_string(p).str^,len+1);
+        getcopy:=p;
+      end;
+
+
+{****************************************************************************
+                               TAI_LABEL
+ ****************************************************************************}
+
+    constructor tai_label.create(_l : tasmlabel);
+      begin
+        inherited Create;
+        typ:=ait_label;
+        l:=_l;
+{        checkredefinesym(l);}
+        l.is_set:=true;
+        is_global:=(l.defbind=AB_GLOBAL);
+      end;
+
+
+    constructor tai_label.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        l:=tasmlabel(ppufile.getasmsymbol);
+        is_global:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure tai_label.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putasmsymbol(l);
+        ppufile.putbyte(byte(is_global));
+      end;
+
+
+    procedure tai_label.derefimpl;
+      begin
+        objectlibrary.DerefAsmsymbol(tasmsymbol(l));
+        l.is_set:=true;
+      end;
+
+
+{****************************************************************************
+                              TAI_DIRECT
+ ****************************************************************************}
+
+     constructor tai_direct.Create(_str : pchar);
+
+       begin
+          inherited Create;
+          typ:=ait_direct;
+          str:=_str;
+       end;
+
+    destructor tai_direct.destroy;
+
+      begin
+         strdispose(str);
+         inherited Destroy;
+      end;
+
+    constructor tai_direct.ppuload(t:taitype;ppufile:tcompilerppufile);
+      var
+        len : longint;
+      begin
+        inherited ppuload(t,ppufile);
+        len:=ppufile.getlongint;
+        getmem(str,len+1);
+        ppufile.getdata(str^,len);
+        str[len]:=#0;
+      end;
+
+
+    procedure tai_direct.ppuwrite(ppufile:tcompilerppufile);
+      var
+        len : longint;
+      begin
+        inherited ppuwrite(ppufile);
+        len:=strlen(str);
+        ppufile.putlongint(len);
+        ppufile.putdata(str^,len);
+      end;
+
+
+    function tai_direct.getcopy : tlinkedlistitem;
+      var
+        p : tlinkedlistitem;
+      begin
+        p:=inherited getcopy;
+        getmem(tai_direct(p).str,strlen(str)+1);
+        move(str^,tai_direct(p).str^,strlen(str)+1);
+        getcopy:=p;
+      end;
+
+
+{****************************************************************************
+          tai_comment  comment to be inserted in the assembler file
+ ****************************************************************************}
+
+     constructor tai_comment.Create(_str : pchar);
+
+       begin
+          inherited Create;
+          typ:=ait_comment;
+          str:=_str;
+       end;
+
+    destructor tai_comment.destroy;
+
+      begin
+         strdispose(str);
+         inherited Destroy;
+      end;
+
+    constructor tai_comment.ppuload(t:taitype;ppufile:tcompilerppufile);
+      var
+        len : longint;
+      begin
+        inherited ppuload(t,ppufile);
+        len:=ppufile.getlongint;
+        getmem(str,len+1);
+        ppufile.getdata(str^,len);
+        str[len]:=#0;
+      end;
+
+
+    procedure tai_comment.ppuwrite(ppufile:tcompilerppufile);
+      var
+        len : longint;
+      begin
+        inherited ppuwrite(ppufile);
+        len:=strlen(str);
+        ppufile.putlongint(len);
+        ppufile.putdata(str^,len);
+      end;
+
+
+    function tai_comment.getcopy : tlinkedlistitem;
+      var
+        p : tlinkedlistitem;
+      begin
+        p:=inherited getcopy;
+        getmem(tai_comment(p).str,strlen(str)+1);
+        move(str^,tai_comment(p).str^,strlen(str)+1);
+        getcopy:=p;
+      end;
+
+
+{****************************************************************************
+                              TAI_CUT
+ ****************************************************************************}
+
+     constructor tai_cut.Create;
+       begin
+          inherited Create;
+          typ:=ait_cut;
+          place:=cut_normal;
+       end;
+
+
+     constructor tai_cut.Create_begin;
+       begin
+          inherited Create;
+          typ:=ait_cut;
+          place:=cut_begin;
+       end;
+
+
+     constructor tai_cut.Create_end;
+       begin
+          inherited Create;
+          typ:=ait_cut;
+          place:=cut_end;
+       end;
+
+
+    constructor tai_cut.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        place:=TCutPlace(ppufile.getbyte);
+      end;
+
+
+    procedure tai_cut.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putbyte(byte(place));
+      end;
+
+
+{****************************************************************************
+                             Tai_Marker
+ ****************************************************************************}
+
+    constructor Tai_Marker.Create(_Kind: TMarker);
+      begin
+        Inherited Create;
+        typ := ait_marker;
+        Kind := _Kind;
+      end;
+
+
+    constructor Tai_Marker.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        kind:=TMarker(ppufile.getbyte);
+      end;
+
+
+    procedure Tai_Marker.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putbyte(byte(kind));
+      end;
+
+
+{*****************************************************************************
+                                tai_tempalloc
+*****************************************************************************}
+
+    constructor tai_tempalloc.alloc(pos,size:longint);
+      begin
+        inherited Create;
+        typ:=ait_tempalloc;
+        allocation:=true;
+        temppos:=pos;
+        tempsize:=size;
+{$ifdef EXTDEBUG}
+        problem:=nil;
+{$endif EXTDEBUG}
+      end;
+
+
+    constructor tai_tempalloc.dealloc(pos,size:longint);
+      begin
+        inherited Create;
+        typ:=ait_tempalloc;
+        allocation:=false;
+        temppos:=pos;
+        tempsize:=size;
+{$ifdef EXTDEBUG}
+        problem:=nil;
+{$endif EXTDEBUG}
+      end;
+
+
+{$ifdef EXTDEBUG}
+    constructor tai_tempalloc.allocinfo(pos,size:longint;const st:string);
+      begin
+        inherited Create;
+        typ:=ait_tempalloc;
+        allocation:=false;
+        temppos:=pos;
+        tempsize:=size;
+        problem:=stringdup(st);
+      end;
+{$endif EXTDEBUG}
+
+
+    constructor tai_tempalloc.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        temppos:=ppufile.getlongint;
+        tempsize:=ppufile.getlongint;
+        allocation:=boolean(ppufile.getbyte);
+{$ifdef EXTDEBUG}
+        problem:=nil;
+{$endif EXTDEBUG}
+      end;
+
+
+    procedure tai_tempalloc.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putlongint(temppos);
+        ppufile.putlongint(tempsize);
+        ppufile.putbyte(byte(allocation));
+      end;
+
+
+{*****************************************************************************
+                                 tai_regalloc
+*****************************************************************************}
+
+    constructor tai_regalloc.alloc(r : tregister);
+      begin
+        inherited create;
+        typ:=ait_regalloc;
+        allocation:=true;
+        reg:=r;
+      end;
+
+
+    constructor tai_regalloc.dealloc(r : tregister);
+      begin
+        inherited create;
+        typ:=ait_regalloc;
+        allocation:=false;
+        reg:=r;
+      end;
+
+
+    constructor tai_regalloc.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        ppufile.getdata(reg,sizeof(Tregister));
+        allocation:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure tai_regalloc.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putdata(reg,sizeof(Tregister));
+        ppufile.putbyte(byte(allocation));
+      end;
+
+
+{*****************************************************************************
+                               TaiInstruction
+*****************************************************************************}
+
+    constructor taicpu_abstract.Create(op : tasmop);
+
+      begin
+         inherited create;
+         typ:=ait_instruction;
+         is_jmp:=false;
+         opcode:=op;
+         ops:=0;
+         fillchar(condition,sizeof(condition),0);
+         fillchar(oper,sizeof(oper),0);
+      end;
+
+
+    destructor taicpu_abstract.Destroy;
+
+      var
+        i : longint;
+      begin
+        for i:=0 to ops-1 do
+        case oper[i].typ of
+          top_ref:
+            dispose(oper[i].ref);
+        end;
+        inherited destroy;
+      end;
+
+
+{ ---------------------------------------------------------------------
+    Loading of operands.
+  ---------------------------------------------------------------------}
+
+    procedure taicpu_abstract.loadconst(opidx:longint;l:aword);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+         begin
+           if typ=top_ref then
+            dispose(ref);
+           val:=l;
+           typ:=top_const;
+         end;
+      end;
+
+
+    procedure taicpu_abstract.loadsymbol(opidx:longint;s:tasmsymbol;sofs:longint);
+      begin
+        if not assigned(s) then
+         internalerror(200204251);
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+         begin
+           if typ=top_ref then
+            dispose(ref);
+           sym:=s;
+           symofs:=sofs;
+           typ:=top_symbol;
+         end;
+        s.increfs;
+      end;
+
+
+    procedure taicpu_abstract.loadref(opidx:longint;const r:treference);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+          begin
+            if typ<>top_ref then
+              new(ref);
+            ref^:=r;
+{$ifdef i386}
+            { We allow this exception for i386, since overloading this would be
+              too much of a a speed penalty}
+            if ref^.segment.enum=R_INTREGISTER then
+              begin
+                if (ref^.segment.number <> NR_NO) and (ref^.segment.number <> NR_DS) then
+                  segprefix:=ref^.segment;
+              end
+            else
+              if not(ref^.segment.enum in [R_DS,R_NO]) then
+                segprefix:=ref^.segment;
+{$endif}
+            typ:=top_ref;
+            { mark symbol as used }
+            if assigned(ref^.symbol) then
+              ref^.symbol.increfs;
+          end;
+      end;
+
+
+    procedure taicpu_abstract.loadreg(opidx:longint;r:tregister);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+         begin
+           if typ=top_ref then
+            dispose(ref);
+           reg:=r;
+           typ:=top_reg;
+         end;
+      end;
+
+
+    procedure taicpu_abstract.loadoper(opidx:longint;o:toper);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        if oper[opidx].typ=top_ref then
+         dispose(oper[opidx].ref);
+        oper[opidx]:=o;
+        { copy also the reference }
+        if oper[opidx].typ=top_ref then
+         begin
+           new(oper[opidx].ref);
+           oper[opidx].ref^:=o.ref^;
+         end;
+      end;
+
+
+{ ---------------------------------------------------------------------
+    Miscellaneous methods.
+  ---------------------------------------------------------------------}
+
+    procedure taicpu_abstract.SetCondition(const c:TAsmCond);
+      begin
+         condition:=c;
+      end;
+
+
+    Function taicpu_abstract.getcopy:TLinkedListItem;
+      var
+        i : longint;
+        p : TLinkedListItem;
+      begin
+        p:=inherited getcopy;
+        { make a copy of the references }
+        for i:=1 to ops do
+         if (taicpu_abstract(p).oper[i-1].typ=top_ref) then
+          begin
+            new(taicpu_abstract(p).oper[i-1].ref);
+            taicpu_abstract(p).oper[i-1].ref^:=oper[i-1].ref^;
+          end;
+        getcopy:=p;
+      end;
+
+
+    constructor taicpu_abstract.ppuload(t:taitype;ppufile:tcompilerppufile);
+      var
+        i : integer;
+      begin
+        inherited ppuload(t,ppufile);
+        { hopefully, we don't get problems with big/litte endian here when cross compiling :/ }
+        ppufile.getdata(condition,sizeof(tasmcond));
+        ops:=ppufile.getbyte;
+        for i:=1 to ops do
+          ppuloadoper(ppufile,oper[i-1]);
+        opcode:=tasmop(ppufile.getword);
+{$ifdef i386}
+        ppufile.getdata(segprefix,sizeof(Tregister));
+{$endif i386}
+        is_jmp:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure taicpu_abstract.ppuwrite(ppufile:tcompilerppufile);
+      var
+        i : integer;
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putdata(condition,sizeof(tasmcond));
+        ppufile.putbyte(ops);
+        for i:=1 to ops do
+          ppuwriteoper(ppufile,oper[i-1]);
+        ppufile.putword(word(opcode));
+{$ifdef i386}
+        ppufile.putdata(segprefix,sizeof(Tregister));
+{$endif i386}
+        ppufile.putbyte(byte(is_jmp));
+      end;
+
+
+    procedure taicpu_abstract.derefimpl;
+      var
+        i : integer;
+      begin
+        for i:=1 to ops do
+          ppuderefoper(oper[i-1]);
+      end;
+
+
+{****************************************************************************
+                              tai_align_abstract
+ ****************************************************************************}
+
+     constructor tai_align_abstract.Create(b: byte);
+       begin
+          inherited Create;
+          typ:=ait_align;
+          if b in [1,2,4,8,16,32] then
+            aligntype := b
+          else
+            aligntype := 1;
+          fillsize:=0;
+          fillop:=0;
+          use_op:=false;
+       end;
+
+
+     constructor tai_align_abstract.Create_op(b: byte; _op: byte);
+       begin
+          inherited Create;
+          typ:=ait_align;
+          if b in [1,2,4,8,16,32] then
+            aligntype := b
+          else
+            aligntype := 1;
+          fillsize:=0;
+          fillop:=_op;
+          use_op:=true;
+       end;
+
+
+     function tai_align_abstract.calculatefillbuf(var buf : tfillbuffer):pchar;
+       begin
+         fillchar(buf,high(buf),fillop);
+         calculatefillbuf:=pchar(@buf);
+       end;
+
+
+    constructor tai_align_abstract.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        aligntype:=ppufile.getbyte;
+        fillsize:=0;
+        fillop:=ppufile.getbyte;
+        use_op:=boolean(ppufile.getbyte);
+      end;
+
+
+    procedure tai_align_abstract.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putbyte(aligntype);
+        ppufile.putbyte(fillop);
+        ppufile.putbyte(byte(use_op));
+      end;
+
+
+{*****************************************************************************
+                                 TAAsmOutput
+*****************************************************************************}
+
+    function taasmoutput.getlasttaifilepos : pfileposinfo;
+      var
+       hp : tlinkedlistitem;
+      begin
+         getlasttaifilepos := nil;
+         if assigned(last) then
+           begin
+              { find the last file information record }
+              if not (tai(last).typ in SkipLineInfo) then
+                 getlasttaifilepos:=@tailineinfo(last).fileinfo
+              else
+               { go through list backwards to find the first entry
+                 with line information
+               }
+               begin
+                 hp:=tai(last);
+                 while assigned(hp) and (tai(hp).typ in SkipLineInfo) do
+                    hp:=hp.Previous;
+                 { found entry }
+                 if assigned(hp) then
+                     getlasttaifilepos:=@tailineinfo(hp).fileinfo
+               end;
+           end;
+      end;
+
+    procedure Taasmoutput.convert_registers;
+
+    var p:Tai;
+        i:shortint;
+        r:Preference;
+
+    begin
+      p:=Tai(first);
+      while assigned(p) do
+        begin
+          case p.typ of
+            ait_regalloc:
+              convert_register_to_enum(Tai_regalloc(p).reg);
+            ait_instruction:
+              begin
+                for i:=0 to Taicpu_abstract(p).ops-1 do
+                  if Taicpu_abstract(p).oper[i].typ=Top_reg then
+                    begin
+                      if Taicpu_abstract(p).oper[i].reg.enum=R_NO then
+                        internalerror(200302052);
+                      convert_register_to_enum(Taicpu_abstract(p).oper[i].reg)
+                    end
+                  else if Taicpu_abstract(p).oper[i].typ=Top_ref then
+                    begin
+                      r:=Taicpu_abstract(p).oper[i].ref;
+                   {$ifdef i386}
+                      convert_register_to_enum(r^.segment);
+                   {$endif i386}
+                      convert_register_to_enum(r^.base);
+                      convert_register_to_enum(r^.index);
+                    end;
+              {$ifdef i386}
+                convert_register_to_enum(Taicpu_abstract(p).segprefix);
+              {$endif}
+              end;
+          end;
+          p:=Tai(p.next);
+        end;
+    end;
+
+    procedure Taasmoutput.translate_registers(const table:Ttranstable);
+
+    var p,q:Tai;
+        i:shortint;
+        r:Preference;
+
+    begin
+      p:=Tai(first);
+      while assigned(p) do
+        begin
+          case p.typ of
+            ait_regalloc:
+              Tai_regalloc(p).reg.number:=(Tai_regalloc(p).reg.number and $ff) or
+                                          (table[Tai_regalloc(p).reg.number shr 8] shl 8);
+            ait_instruction:
+              begin
+                for i:=0 to Taicpu_abstract(p).ops-1 do
+                  if Taicpu_abstract(p).oper[i].typ=Top_reg then
+                    Taicpu_abstract(p).oper[i].reg.number:=(Taicpu_abstract(p).oper[i].reg.number and $ff) or
+                                                           (table[Taicpu_abstract(p).oper[i].reg.number shr 8] shl 8)
+                  else if Taicpu_abstract(p).oper[i].typ=Top_ref then
+                    begin
+                      r:=Taicpu_abstract(p).oper[i].ref;
+                      if r^.base.number<>NR_NO then
+                        r^.base.number:=(r^.base.number and $ff) or
+                                        (table[r^.base.number shr 8] shl 8);
+                      if r^.index.number<>NR_NO then
+                        r^.index.number:=(r^.index.number and $ff) or
+                                         (table[r^.index.number shr 8] shl 8);
+                    end;
+                if Taicpu_abstract(p).is_nop then
+                  begin
+                    q:=p;
+                    p:=Tai(p.next);
+                    remove(q);
+                    continue;
+                  end;
+              end;
+          end;
+          p:=Tai(p.next);
+        end;
+    end;
+
+end.
+{
+  $Log$
+  Revision 1.26  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.25  2003/04/25 08:25:26  daniel
+    * Ifdefs around a lot of calls to cleartempgen
+    * Fixed registers that are allocated but not freed in several nodes
+    * Tweak to register allocator to cause less spills
+    * 8-bit registers now interfere with esi,edi and ebp
+      Compiler can now compile rtl successfully when using new register
+      allocator
+
+  Revision 1.24  2003/04/24 13:03:01  florian
+    * comp is now written with its bit pattern to the ppu instead as an extended
+
+  Revision 1.23  2003/04/22 14:33:38  peter
+    * removed some notes/hints
+
+  Revision 1.22  2003/04/22 10:09:34  daniel
+    + Implemented the actual register allocator
+    + Scratch registers unavailable when new register allocator used
+    + maybe_save/maybe_restore unavailable when new register allocator used
+
+  Revision 1.21  2003/02/19 22:00:14  daniel
+    * Code generator converted to new register notation
+    - Horribily outdated todo.txt removed
+
+  Revision 1.20  2003/01/30 21:46:20  peter
+    * tai_const_symbol.createdataname added
+
+  Revision 1.19  2003/01/21 08:48:08  daniel
+    * Another 200301081 fixed
+
+  Revision 1.18  2003/01/09 20:40:59  daniel
+    * Converted some code in cgx86.pas to new register numbering
+
+  Revision 1.17  2003/01/09 15:49:56  daniel
+    * Added register conversion
+
+  Revision 1.16  2003/01/08 18:43:56  daniel
+   * Tregister changed into a record
+
+  Revision 1.15  2003/01/05 13:36:53  florian
+    * x86-64 compiles
+    + very basic support for float128 type (x86-64 only)
+
+  Revision 1.14  2002/12/06 17:50:21  peter
+    * symbol count fix merged
+
+  Revision 1.13  2002/11/17 16:31:55  carl
+    * memory optimization (3-4%) : cleanup of tai fields,
+       cleanup of tdef and tsym fields.
+    * make it work for m68k
+
+  Revision 1.12  2002/11/15 16:29:30  peter
+    * made tasmsymbol.refs private (merged)
+
+  Revision 1.11  2002/11/15 01:58:45  peter
+    * merged changes from 1.0.7 up to 04-11
+      - -V option for generating bug report tracing
+      - more tracing for option parsing
+      - errors for cdecl and high()
+      - win32 import stabs
+      - win32 records<=8 are returned in eax:edx (turned off by default)
+      - heaptrc update
+      - more info for temp management in .s file with EXTDEBUG
+
+  Revision 1.10  2002/11/09 15:38:03  carl
+    + NOOPT removed the optinfo field
+
+  Revision 1.9  2002/10/05 12:43:23  carl
+    * fixes for Delphi 6 compilation
+     (warning : Some features do not work under Delphi)
+
+  Revision 1.8  2002/08/19 19:36:42  peter
+    * More fixes for cross unit inlining, all tnodes are now implemented
+    * Moved pocall_internconst to po_internconst because it is not a
+      calling type at all and it conflicted when inlining of these small
+      functions was requested
+
+  Revision 1.7  2002/08/18 20:06:23  peter
+    * inlining is now also allowed in interface
+    * renamed write/load to ppuwrite/ppuload
+    * tnode storing in ppu
+    * nld,ncon,nbas are already updated for storing in ppu
+
+  Revision 1.6  2002/08/16 05:21:09  florian
+    * powerpc compilation fix
+
+  Revision 1.5  2002/08/15 19:10:35  peter
+    * first things tai,tnode storing in ppu
+
+  Revision 1.4  2002/08/11 14:32:25  peter
+    * renamed current_library to objectlibrary
+
+  Revision 1.3  2002/08/11 13:24:10  peter
+    * saving of asmsymbols in ppu supported
+    * asmsymbollist global is removed and moved into a new class
+      tasmlibrarydata that will hold the info of a .a file which
+      corresponds with a single module. Added librarydata to tmodule
+      to keep the library info stored for the module. In the future the
+      objectfiles will also be stored to the tasmlibrarydata class
+    * all getlabel/newasmsymbol and friends are moved to the new class
+
+  Revision 1.2  2002/08/05 18:27:48  carl
+    + more more more documentation
+    + first version include/exclude (can't test though, not enough scratch for i386 :()...
+
+  Revision 1.1  2002/07/01 18:46:20  peter
+    * internal linker
+    * reorganized aasm layer
+
+  Revision 1.27  2002/05/18 13:34:04  peter
+    * readded missing revisions
+
+  Revision 1.25  2002/05/14 19:34:38  peter
+    * removed old logs and updated copyright year
+
+  Revision 1.24  2002/05/14 17:28:08  peter
+    * synchronized cpubase between powerpc and i386
+    * moved more tables from cpubase to cpuasm
+    * tai_align_abstract moved to tainst, cpuasm must define
+      the tai_align class now, which may be empty
+
+  Revision 1.23  2002/04/15 18:54:34  carl
+  - removed tcpuflags
+
+  Revision 1.22  2002/04/07 13:18:19  carl
+  + more documentation
+
+  Revision 1.21  2002/04/07 10:17:40  carl
+  - remove packenumfixed (requires version 1.0.2 or later to compile now!)
+  + changing some comments so its commented automatically
+
+  Revision 1.20  2002/03/24 19:04:31  carl
+  + patch for SPARC from Mazen NEIFER
+
+}

+ 211 - 0
compiler/i386/cpubase.inc

@@ -0,0 +1,211 @@
+{
+    $Id$
+    Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
+
+    Contains the basic declarations for the i386 architecture
+
+    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 include file contains the basic declarations for the i386 architecture.
+}
+
+
+{*****************************************************************************
+                                Operand Sizes
+*****************************************************************************}
+
+    type
+      topsize = (S_NO,
+        S_B,S_W,S_L,S_BW,S_BL,S_WL,
+        S_IS,S_IL,S_IQ,
+        S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX,
+        S_NEAR,S_FAR,S_SHORT
+      );
+
+{*****************************************************************************
+                                Registers
+*****************************************************************************}
+  const
+      {# Standard opcode string table (for each tasmop enumeration). The
+         opcode strings should conform to the names as defined by the
+         processor manufacturer.
+      }
+      std_op2str:op2strtable={$i i386int.inc}
+
+      {# Standard register table (for each tregister enumeration). The
+         register strings should conform to the the names as defined
+         by the processor manufacturer
+      }
+      std_reg2str : reg2strtable = ('',
+        'eax','ecx','edx','ebx','esp','ebp','esi','edi',
+        'ax','cx','dx','bx','sp','bp','si','di',
+        'al','cl','dl','bl','ah','ch','bh','dh',
+        'cs','ds','es','ss','fs','gs',
+        'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)',
+        'dr0','dr1','dr2','dr3','dr6','dr7',
+        'cr0','cr2','cr3','cr4',
+        'tr3','tr4','tr5','tr6','tr7',
+        'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
+        'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
+      );
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+      firstsaveintreg = RS_EAX;
+      lastsaveintreg  = RS_EDX;
+      firstsavefpureg = R_NO;
+      lastsavefpureg  = R_NO;
+      firstsavemmreg  = R_MM0;
+      lastsavemmreg   = R_MM7;
+
+      general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
+      general_superregisters = [RS_EAX,RS_EBX,RS_ECX,RS_EDX];
+
+{$ifdef newra}
+      usableregsint = [first_imreg..last_imreg];
+{$else}
+      usableregsint = [RS_EAX,RS_EBX,RS_ECX,RS_EDX];
+{$endif}
+      c_countusableregsint = 4;
+
+      maxaddrregs = 1;
+      addrregs    = [R_ESI];
+      usableregsaddr = [RS_ESI];
+      c_countusableregsaddr = 1;
+
+      maxvarregs = 4;
+      varregs : array[1..maxvarregs] of Toldregister =
+         (R_EBX,R_EDX,R_ECX,R_EAX);
+
+      maxfpuvarregs = 8;
+
+      {# Registers which are defined as scratch and no need to save across
+         routine calls or in assembler blocks.
+      }
+{$ifndef newra}
+      max_scratch_regs = 1;
+      scratch_regs : array[1..max_scratch_regs] of Tsuperregister = (RS_EDI);
+{$endif}
+{*****************************************************************************
+                               GDB Information
+*****************************************************************************}
+
+      {# Register indexes for stabs information, when some
+         parameters or variables are stored in registers.
+
+         Taken from i386.c (dbx_register_map) and i386.h
+          (FIXED_REGISTERS) from GCC 3.x source code
+
+      }
+      stab_regindex : array[firstreg..lastreg] of shortint =
+        (-1,
+        0,1,2,3,4,5,6,7,
+        0,1,2,3,4,5,6,7,
+        0,1,2,3,0,1,2,3,
+        -1,-1,-1,-1,-1,-1,
+        12,12,13,14,15,16,17,18,19,
+        -1,-1,-1,-1,-1,-1,
+        -1,-1,-1,-1,
+        -1,-1,-1,-1,-1,
+        29,30,31,32,33,34,35,36,
+        21,22,23,24,25,26,27,28
+      );
+
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+      {# Defines the default address size for a processor, }
+      OS_ADDR = OS_32;
+      {# the natural int size for a processor,             }
+      OS_INT = OS_32;
+      {# the maximum float size for a processor,           }
+      OS_FLOAT = OS_F80;
+      {# the size of a vector register for a processor     }
+      OS_VECTOR = OS_M64;
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      {# Stack pointer register }
+      stack_pointer_reg = R_ESP;
+      NR_STACK_POINTER_REG = NR_ESP;
+      {# Frame pointer register }
+      frame_pointer_reg = R_EBP;
+      NR_FRAME_POINTER_REG = NR_EBP;
+      {# Register for addressing absolute data in a position independant way,
+         such as in PIC code. The exact meaning is ABI specific. For
+         further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
+      }
+      pic_offset_reg = R_EBX;
+      {# Results are returned in this register (32-bit values) }
+      accumulator   = R_EAX;
+      RS_ACCUMULATOR   = RS_EAX;
+      NR_ACCUMULATOR   = NR_EAX;
+      { The return_result_reg is used inside the called function to store its return
+        value when that is a scalar value otherwise a pointer to the address of the
+        result is placed inside it}
+      return_result_reg = accumulator;
+      RS_RETURN_RESULT_REG = RS_ACCUMULATOR;
+      NR_RETURN_RESULT_REG = NR_ACCUMULATOR;
+
+      {the function_result_reg contains the function result after a call to a scalar
+      function othewise it contains a pointer to the returned result}
+        function_result_reg     =       accumulator;
+      {# Hi-Results are returned in this register (64-bit value high register) }
+      accumulatorhigh = R_EDX;
+      RS_ACCUMULATORHIGH  = RS_EDX;
+      NR_ACCUMULATORHIGH  = NR_EDX;
+      { WARNING: don't change to R_ST0!! See comments above implementation of }
+      { a_loadfpu* methods in rgcpu (JM)                                      }
+      fpu_result_reg = R_ST;
+      mmresultreg = R_MM0;
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+    const
+      {# Registers which must be saved when calling a routine declared as
+         cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+         saved should be the ones as defined in the target ABI and / or GCC.
+
+         This value can be deduced from the CALLED_USED_REGISTERS array in the
+         GCC source.
+      }
+      std_saved_registers = [R_ESI,R_EDI,R_EBX];
+      {# Required parameter alignment when calling a routine declared as
+         stdcall and cdecl. The alignment value should be the one defined
+         by GCC or the target ABI.
+
+         The value of this constant is equal to the constant
+         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+      }
+      std_param_align = 4;
+
+{
+  $Log$
+  Revision 1.2  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.1  2003/04/25 11:12:09  florian
+    * merged i386/cpubase and x86_64/cpubase to x86/cpubase;
+      different stuff went to cpubase.inc
+}

+ 2109 - 0
compiler/x86/aasmcpu.pas

@@ -0,0 +1,2109 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
+
+    Contains the abstract assembler implementation for the i386
+
+    * Portions of this code was inspired by the NASM sources
+      The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
+      Julian Hall. All rights reserved.
+
+    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.
+
+ ****************************************************************************
+}
+unit aasmcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cclasses,globals,verbose,
+      cpuinfo,cpubase,
+      symppu,
+      aasmbase,aasmtai;
+
+    const
+    { Operand types }
+      OT_NONE      = $00000000;
+
+      OT_BITS8     = $00000001;  { size, and other attributes, of the operand  }
+      OT_BITS16    = $00000002;
+      OT_BITS32    = $00000004;
+      OT_BITS64    = $00000008;  { FPU only  }
+      OT_BITS80    = $00000010;
+      OT_FAR       = $00000020;  { this means 16:16 or 16:32, like in CALL/JMP }
+      OT_NEAR      = $00000040;
+      OT_SHORT     = $00000080;
+
+      OT_SIZE_MASK = $000000FF;  { all the size attributes  }
+      OT_NON_SIZE  = longint(not OT_SIZE_MASK);
+
+      OT_SIGNED    = $00000100;  { the operand need to be signed -128-127 }
+
+      OT_TO        = $00000200;  { operand is followed by a colon  }
+                                 { reverse effect in FADD, FSUB &c  }
+      OT_COLON     = $00000400;
+
+      OT_REGISTER  = $00001000;
+      OT_IMMEDIATE = $00002000;
+      OT_IMM8      = $00002001;
+      OT_IMM16     = $00002002;
+      OT_IMM32     = $00002004;
+      OT_IMM64     = $00002008;
+      OT_IMM80     = $00002010;
+      OT_REGMEM    = $00200000;  { for r/m, ie EA, operands  }
+      OT_REGNORM   = $00201000;  { 'normal' reg, qualifies as EA  }
+      OT_REG8      = $00201001;
+      OT_REG16     = $00201002;
+      OT_REG32     = $00201004;
+{$ifdef x86_64}
+      OT_REG64     = $00201008;
+{$endif x86_64}
+      OT_MMXREG    = $00201008;  { MMX registers  }
+      OT_XMMREG    = $00201010;  { Katmai registers  }
+      OT_MEMORY    = $00204000;  { register number in 'basereg'  }
+      OT_MEM8      = $00204001;
+      OT_MEM16     = $00204002;
+      OT_MEM32     = $00204004;
+      OT_MEM64     = $00204008;
+      OT_MEM80     = $00204010;
+      OT_FPUREG    = $01000000;  { floating point stack registers  }
+      OT_FPU0      = $01000800;  { FPU stack register zero  }
+      OT_REG_SMASK = $00070000;  { special register operands: these may be treated differently  }
+                                 { a mask for the following  }
+      OT_REG_ACCUM = $00211000;  { accumulator: AL, AX or EAX  }
+      OT_REG_AL    = $00211001;    { REG_ACCUM | BITSxx  }
+      OT_REG_AX    = $00211002;    { ditto  }
+      OT_REG_EAX   = $00211004;    { and again  }
+{$ifdef x86_64}
+      OT_REG_RAX   = $00211008;
+{$endif x86_64}
+      OT_REG_COUNT = $00221000;  { counter: CL, CX or ECX  }
+      OT_REG_CL    = $00221001;    { REG_COUNT | BITSxx  }
+      OT_REG_CX    = $00221002;    { ditto  }
+      OT_REG_ECX   = $00221004;    { another one  }
+{$ifdef x86_64}
+      OT_REG_RCX   = $00221008;
+{$endif x86_64}
+      OT_REG_DX    = $00241002;
+
+      OT_REG_SREG  = $00081002;  { any segment register  }
+      OT_REG_CS    = $01081002;  { CS  }
+      OT_REG_DESS  = $02081002;  { DS, ES, SS (non-CS 86 registers)  }
+      OT_REG_FSGS  = $04081002;  { FS, GS (386 extended registers)  }
+
+      OT_REG_CDT   = $00101004;  { CRn, DRn and TRn  }
+      OT_REG_CREG  = $08101004;  { CRn  }
+      OT_REG_CR4   = $08101404;  { CR4 (Pentium only)  }
+      OT_REG_DREG  = $10101004;  { DRn  }
+      OT_REG_TREG  = $20101004;  { TRn  }
+
+      OT_MEM_OFFS  = $00604000;  { special type of EA  }
+                                 { simple [address] offset  }
+      OT_ONENESS   = $00800000;  { special type of immediate operand  }
+                                 { so UNITY == IMMEDIATE | ONENESS  }
+      OT_UNITY     = $00802000;  { for shift/rotate instructions  }
+
+      { Size of the instruction table converted by nasmconv.pas }
+{$ifdef x86_64}
+      instabentries = {$i x86_64no.inc}
+{$else x86_64}
+      instabentries = {$i i386nop.inc}
+{$endif x86_64}
+      maxinfolen    = 8;
+
+    type
+      TOperandOrder = (op_intel,op_att);
+
+      tinsentry=packed record
+        opcode  : tasmop;
+        ops     : byte;
+        optypes : array[0..2] of longint;
+        code    : array[0..maxinfolen] of char;
+        flags   : longint;
+      end;
+      pinsentry=^tinsentry;
+
+      { alignment for operator }
+      tai_align = class(tai_align_abstract)
+         reg       : tregister;
+         constructor create(b:byte);
+         constructor create_op(b: byte; _op: byte);
+         function calculatefillbuf(var buf : tfillbuffer):pchar;override;
+      end;
+
+      taicpu = class(taicpu_abstract)
+         opsize    : topsize;
+         constructor op_none(op : tasmop;_size : topsize);
+
+         constructor op_reg(op : tasmop;_size : topsize;_op1 : tregister);
+         constructor op_const(op : tasmop;_size : topsize;_op1 : aword);
+         constructor op_ref(op : tasmop;_size : topsize;const _op1 : treference);
+
+         constructor op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
+         constructor op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;const _op2 : treference);
+         constructor op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: aword);
+
+         constructor op_const_reg(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister);
+         constructor op_const_const(op : tasmop;_size : topsize;_op1,_op2 : aword);
+         constructor op_const_ref(op : tasmop;_size : topsize;_op1 : aword;const _op2 : treference);
+
+         constructor op_ref_reg(op : tasmop;_size : topsize;const _op1 : treference;_op2 : tregister);
+
+         constructor op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
+         constructor op_const_reg_reg(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister;_op3 : tregister);
+         constructor op_const_ref_reg(op : tasmop;_size : topsize;_op1 : aword;const _op2 : treference;_op3 : tregister);
+         constructor op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister; const _op3 : treference);
+         constructor op_const_reg_ref(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister;const _op3 : treference);
+
+         { this is for Jmp instructions }
+         constructor op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
+
+         constructor op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
+         constructor op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
+         constructor op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
+         constructor op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
+
+         procedure changeopsize(siz:topsize);
+
+         function  GetString:string;
+         procedure CheckNonCommutativeOpcodes;
+      private
+         FOperandOrder : TOperandOrder;
+         procedure init(_size : topsize); { this need to be called by all constructor }
+    {$ifndef NOAG386BIN}
+      public
+         { the next will reset all instructions that can change in pass 2 }
+         procedure ResetPass1;
+         procedure ResetPass2;
+         function  CheckIfValid:boolean;
+         function  Pass1(offset:longint):longint;virtual;
+         procedure Pass2(sec:TAsmObjectdata);virtual;
+         procedure SetOperandOrder(order:TOperandOrder);
+      protected
+         procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);override;
+         procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override;
+         procedure ppuderefoper(var o:toper);override;
+      private
+         { next fields are filled in pass1, so pass2 is faster }
+         insentry  : PInsEntry;
+         insoffset,
+         inssize   : longint;
+         LastInsOffset : longint; { need to be public to be reset }
+         function  InsEnd:longint;
+         procedure create_ot;
+         function  Matches(p:PInsEntry):longint;
+         function  calcsize(p:PInsEntry):longint;
+         procedure gencode(sec:TAsmObjectData);
+         function  NeedAddrPrefix(opidx:byte):boolean;
+         procedure Swapoperands;
+    {$endif NOAG386BIN}
+         function is_nop:boolean;override;
+      end;
+
+
+    procedure InitAsm;
+    procedure DoneAsm;
+
+
+implementation
+
+     uses
+       cutils,
+       agx86att;
+
+{*****************************************************************************
+                              Instruction table
+*****************************************************************************}
+
+    const
+     {Instruction flags }
+       IF_NONE   = $00000000;
+       IF_SM     = $00000001;        { size match first two operands  }
+       IF_SM2    = $00000002;
+       IF_SB     = $00000004;  { unsized operands can't be non-byte  }
+       IF_SW     = $00000008;  { unsized operands can't be non-word  }
+       IF_SD     = $00000010;  { unsized operands can't be nondword  }
+       IF_AR0    = $00000020;  { SB, SW, SD applies to argument 0  }
+       IF_AR1    = $00000040;  { SB, SW, SD applies to argument 1  }
+       IF_AR2    = $00000060;  { SB, SW, SD applies to argument 2  }
+       IF_ARMASK = $00000060;  { mask for unsized argument spec  }
+       IF_PRIV   = $00000100;  { it's a privileged instruction  }
+       IF_SMM    = $00000200;  { it's only valid in SMM  }
+       IF_PROT   = $00000400;  { it's protected mode only  }
+       IF_UNDOC  = $00001000;  { it's an undocumented instruction  }
+       IF_FPU    = $00002000;  { it's an FPU instruction  }
+       IF_MMX    = $00004000;  { it's an MMX instruction  }
+       { it's a 3DNow! instruction  }
+       IF_3DNOW  = $00008000;
+       { it's a SSE (KNI, MMX2) instruction  }
+       IF_SSE    = $00010000;
+       { SSE2 instructions  }
+       IF_SSE2   = $00020000;
+       { the mask for processor types  }
+       {IF_PMASK  = longint($FF000000);}
+       { the mask for disassembly "prefer"  }
+       {IF_PFMASK = longint($F001FF00);}
+       IF_8086   = $00000000;  { 8086 instruction  }
+       IF_186    = $01000000;  { 186+ instruction  }
+       IF_286    = $02000000;  { 286+ instruction  }
+       IF_386    = $03000000;  { 386+ instruction  }
+       IF_486    = $04000000;  { 486+ instruction  }
+       IF_PENT   = $05000000;  { Pentium instruction  }
+       IF_P6     = $06000000;  { P6 instruction  }
+       IF_KATMAI = $07000000;  { Katmai instructions  }
+       { Willamette instructions }
+       IF_WILLAMETTE = $08000000;
+       IF_CYRIX  = $10000000;  { Cyrix-specific instruction  }
+       IF_AMD    = $20000000;  { AMD-specific instruction  }
+       { added flags }
+       IF_PRE    = $40000000;  { it's a prefix instruction }
+       IF_PASS2  = longint($80000000);  { if the instruction can change in a second pass }
+
+     type
+       TInsTabCache=array[TasmOp] of longint;
+       PInsTabCache=^TInsTabCache;
+
+     const
+{$ifdef x86_64}
+       InsTab:array[0..instabentries-1] of TInsEntry={$i x86_64ta.inc}
+{$else x86_64}
+       InsTab:array[0..instabentries-1] of TInsEntry={$i i386tab.inc}
+{$endif x86_64}
+     var
+       InsTabCache : PInsTabCache;
+
+     const
+{$ifdef x86_64}
+       { Intel style operands ! }
+       opsize_2_type:array[0..2,topsize] of longint=(
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS16,OT_BITS32,OT_BITS32,OT_BITS64,OT_BITS64,OT_BITS64,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         ),
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS8,OT_BITS8,OT_BITS16,OT_BITS8,OT_BITS16,OT_BITS32,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         ),
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_NONE,OT_NONE,OT_NONE,OT_NONE,OT_NONE,OT_NONE,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         )
+       );
+
+       { Convert reg to operand type }
+       reg2type : array[firstreg..lastreg] of longint = (OT_NONE,
+         OT_REG_RAX,OT_REG_RCX,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,
+         OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,OT_REG64,
+         OT_REG_EAX,OT_REG_ECX,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,
+         OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,
+         OT_REG_AX,OT_REG_CX,OT_REG_DX,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,
+         OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,
+         OT_REG_AL,OT_REG_CL,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,
+         OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,
+         OT_REG8,OT_REG8,OT_REG8,OT_REG8,
+         OT_REG_CS,OT_REG_DESS,OT_REG_DESS,OT_REG_DESS,OT_REG_FSGS,OT_REG_FSGS,
+         OT_FPU0,OT_FPU0,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,
+         OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,
+         OT_REG_CREG,OT_REG_CREG,OT_REG_CREG,OT_REG_CR4,
+         OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,
+         OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,
+         OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,
+         OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG
+       );
+
+      subreg2type:array[R_SUBL..R_SUBQ] of longint = (
+        OT_REG8,OT_REG8,OT_REG16,OT_REG32,OT_REG64
+      );
+
+{$else x86_64}
+       { Intel style operands ! }
+       opsize_2_type:array[0..2,topsize] of longint=(
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS16,OT_BITS32,OT_BITS32,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         ),
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS8,OT_BITS8,OT_BITS16,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         ),
+         (OT_NONE,
+          OT_BITS8,OT_BITS16,OT_BITS32,OT_NONE,OT_NONE,OT_NONE,
+          OT_BITS16,OT_BITS32,OT_BITS64,
+          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64,OT_NONE,
+          OT_NEAR,OT_FAR,OT_SHORT
+         )
+      );
+
+      subreg2type:array[R_SUBL..R_SUBD] of longint = (
+        OT_REG8,OT_REG8,OT_REG16,OT_REG32
+      );
+
+      { Convert reg to operand type }
+      reg2type : array[firstreg..lastreg] of longint = (OT_NONE,
+        OT_REG_EAX,OT_REG_ECX,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,
+        OT_REG_AX,OT_REG_CX,OT_REG_DX,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,
+        OT_REG_AL,OT_REG_CL,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,
+        OT_REG_CS,OT_REG_DESS,OT_REG_DESS,OT_REG_DESS,OT_REG_FSGS,OT_REG_FSGS,
+        OT_FPU0,OT_FPU0,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,
+        OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,
+        OT_REG_CREG,OT_REG_CREG,OT_REG_CREG,OT_REG_CR4,
+        OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,
+        OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,
+        OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG
+      );
+{$endif x86_64}
+
+{****************************************************************************
+                              TAI_ALIGN
+ ****************************************************************************}
+
+    constructor tai_align.create(b: byte);
+      begin
+        inherited create(b);
+        reg.enum := R_ECX;
+      end;
+
+
+    constructor tai_align.create_op(b: byte; _op: byte);
+      begin
+        inherited create_op(b,_op);
+        reg.enum := R_NO;
+      end;
+
+
+    function tai_align.calculatefillbuf(var buf : tfillbuffer):pchar;
+      const
+        alignarray:array[0..5] of string[8]=(
+          #$8D#$B4#$26#$00#$00#$00#$00,
+          #$8D#$B6#$00#$00#$00#$00,
+          #$8D#$74#$26#$00,
+          #$8D#$76#$00,
+          #$89#$F6,
+          #$90
+        );
+      var
+        bufptr : pchar;
+        j : longint;
+      begin
+        inherited calculatefillbuf(buf);
+        if not use_op then
+         begin
+           bufptr:=pchar(@buf);
+           while (fillsize>0) do
+            begin
+              for j:=0 to 5 do
+               if (fillsize>=length(alignarray[j])) then
+                break;
+              move(alignarray[j][1],bufptr^,length(alignarray[j]));
+              inc(bufptr,length(alignarray[j]));
+              dec(fillsize,length(alignarray[j]));
+            end;
+         end;
+        calculatefillbuf:=pchar(@buf);
+      end;
+
+
+{*****************************************************************************
+                                 Taicpu Constructors
+*****************************************************************************}
+
+    procedure taicpu.changeopsize(siz:topsize);
+      begin
+        opsize:=siz;
+      end;
+
+
+    procedure taicpu.init(_size : topsize);
+      begin
+         { default order is att }
+         FOperandOrder:=op_att;
+         segprefix.enum:=R_NO;
+         opsize:=_size;
+{$ifndef NOAG386BIN}
+         insentry:=nil;
+         LastInsOffset:=-1;
+         InsOffset:=0;
+         InsSize:=0;
+{$endif}
+      end;
+
+
+    constructor taicpu.op_none(op : tasmop;_size : topsize);
+      begin
+         inherited create(op);
+         init(_size);
+      end;
+
+
+    constructor taicpu.op_reg(op : tasmop;_size : topsize;_op1 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=1;
+         loadreg(0,_op1);
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_size : topsize;_op1 : aword);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=1;
+         loadconst(0,_op1);
+      end;
+
+
+    constructor taicpu.op_ref(op : tasmop;_size : topsize;const _op1 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=1;
+         loadref(0,_op1);
+      end;
+
+
+    constructor taicpu.op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: aword);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;const _op2 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadreg(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_reg(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_const(op : tasmop;_size : topsize;_op1,_op2 : aword);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_ref(op : tasmop;_size : topsize;_op1 : aword;const _op2 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadconst(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_ref_reg(op : tasmop;_size : topsize;const _op1 : treference;_op2 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadref(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+
+    constructor taicpu.op_const_reg_reg(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister;_op3 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+
+    constructor taicpu.op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister;const _op3 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+
+    constructor taicpu.op_const_ref_reg(op : tasmop;_size : topsize;_op1 : aword;const _op2 : treference;_op3 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=3;
+         loadconst(0,_op1);
+         loadref(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+
+    constructor taicpu.op_const_reg_ref(op : tasmop;_size : topsize;_op1 : aword;_op2 : tregister;const _op3 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+
+    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         init(_size);
+         condition:=cond;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=1;
+         loadsymbol(0,_op1,_op1ofs);
+      end;
+
+
+    constructor taicpu.op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadsymbol(0,_op1,_op1ofs);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
+      begin
+         inherited create(op);
+         init(_size);
+         ops:=2;
+         loadsymbol(0,_op1,_op1ofs);
+         loadref(1,_op2);
+      end;
+
+
+    function taicpu.GetString:string;
+      var
+        i : longint;
+        s : string;
+        addsize : boolean;
+      begin
+        s:='['+std_op2str[opcode];
+        for i:=1to ops do
+         begin
+           if i=1 then
+            s:=s+' '
+           else
+            s:=s+',';
+           { type }
+           addsize:=false;
+           if (oper[i-1].ot and OT_XMMREG)=OT_XMMREG then
+            s:=s+'xmmreg'
+           else
+             if (oper[i-1].ot and OT_MMXREG)=OT_MMXREG then
+              s:=s+'mmxreg'
+           else
+             if (oper[i-1].ot and OT_FPUREG)=OT_FPUREG then
+              s:=s+'fpureg'
+           else
+            if (oper[i-1].ot and OT_REGISTER)=OT_REGISTER then
+             begin
+               s:=s+'reg';
+               addsize:=true;
+             end
+           else
+            if (oper[i-1].ot and OT_IMMEDIATE)=OT_IMMEDIATE then
+             begin
+               s:=s+'imm';
+               addsize:=true;
+             end
+           else
+            if (oper[i-1].ot and OT_MEMORY)=OT_MEMORY then
+             begin
+               s:=s+'mem';
+               addsize:=true;
+             end
+           else
+             s:=s+'???';
+           { size }
+           if addsize then
+            begin
+              if (oper[i-1].ot and OT_BITS8)<>0 then
+                s:=s+'8'
+              else
+               if (oper[i-1].ot and OT_BITS16)<>0 then
+                s:=s+'16'
+              else
+               if (oper[i-1].ot and OT_BITS32)<>0 then
+                s:=s+'32'
+              else
+                s:=s+'??';
+              { signed }
+              if (oper[i-1].ot and OT_SIGNED)<>0 then
+               s:=s+'s';
+            end;
+         end;
+        GetString:=s+']';
+      end;
+
+
+    procedure taicpu.Swapoperands;
+      var
+        p : TOper;
+      begin
+        { Fix the operands which are in AT&T style and we need them in Intel style }
+        case ops of
+          2 : begin
+                { 0,1 -> 1,0 }
+                p:=oper[0];
+                oper[0]:=oper[1];
+                oper[1]:=p;
+              end;
+          3 : begin
+                { 0,1,2 -> 2,1,0 }
+                p:=oper[0];
+                oper[0]:=oper[2];
+                oper[2]:=p;
+              end;
+        end;
+      end;
+
+
+    procedure taicpu.SetOperandOrder(order:TOperandOrder);
+      begin
+        if FOperandOrder<>order then
+         begin
+           Swapoperands;
+           FOperandOrder:=order;
+         end;
+      end;
+
+
+    procedure taicpu.ppuloadoper(ppufile:tcompilerppufile;var o:toper);
+      begin
+        o.typ:=toptype(ppufile.getbyte);
+        o.ot:=ppufile.getlongint;
+        case o.typ of
+          top_reg :
+              ppufile.getdata(o.reg,sizeof(Tregister));
+          top_ref :
+            begin
+              new(o.ref);
+              ppufile.getdata(o.ref^.segment,sizeof(Tregister));
+              ppufile.getdata(o.ref^.base,sizeof(Tregister));
+              ppufile.getdata(o.ref^.index,sizeof(Tregister));
+              o.ref^.scalefactor:=ppufile.getbyte;
+              o.ref^.offset:=ppufile.getlongint;
+              o.ref^.symbol:=ppufile.getasmsymbol;
+              o.ref^.offsetfixup:=ppufile.getlongint;
+              o.ref^.options:=trefoptions(ppufile.getbyte);
+            end;
+          top_const :
+            o.val:=aword(ppufile.getlongint);
+          top_symbol :
+            begin
+              o.sym:=ppufile.getasmsymbol;
+              o.symofs:=ppufile.getlongint;
+            end;
+        end;
+      end;
+
+
+    procedure taicpu.ppuwriteoper(ppufile:tcompilerppufile;const o:toper);
+      begin
+        ppufile.putbyte(byte(o.typ));
+        ppufile.putlongint(o.ot);
+        case o.typ of
+          top_reg :
+            ppufile.putdata(o.reg,sizeof(Tregister));
+          top_ref :
+            begin
+              ppufile.putdata(o.ref^.segment,sizeof(Tregister));
+              ppufile.putdata(o.ref^.base,sizeof(Tregister));
+              ppufile.putdata(o.ref^.index,sizeof(Tregister));
+              ppufile.putbyte(o.ref^.scalefactor);
+              ppufile.putlongint(o.ref^.offset);
+              ppufile.putasmsymbol(o.ref^.symbol);
+              ppufile.putlongint(o.ref^.offsetfixup);
+              ppufile.putbyte(byte(o.ref^.options));
+            end;
+          top_const :
+            ppufile.putlongint(longint(o.val));
+          top_symbol :
+            begin
+              ppufile.putasmsymbol(o.sym);
+              ppufile.putlongint(longint(o.symofs));
+            end;
+        end;
+      end;
+
+
+    procedure taicpu.ppuderefoper(var o:toper);
+      begin
+        case o.typ of
+          top_ref :
+            begin
+              if assigned(o.ref^.symbol) then
+               objectlibrary.derefasmsymbol(o.ref^.symbol);
+            end;
+          top_symbol :
+            objectlibrary.derefasmsymbol(o.sym);
+        end;
+      end;
+
+
+    procedure taicpu.CheckNonCommutativeOpcodes;
+      begin
+        { we need ATT order }
+        SetOperandOrder(op_att);
+
+        if ((ops=2) and
+           (oper[0].typ=top_reg) and
+           (oper[1].typ=top_reg) and
+           { if the first is ST and the second is also a register
+             it is necessarily ST1 .. ST7 }
+           (oper[0].reg.enum in [R_ST..R_ST0])) or
+           { ((ops=1) and
+            (oper[0].typ=top_reg) and
+            (oper[0].reg in [R_ST1..R_ST7]))  or}
+           (ops=0) then
+            if opcode=A_FSUBR then
+              opcode:=A_FSUB
+            else if opcode=A_FSUB then
+              opcode:=A_FSUBR
+            else if opcode=A_FDIVR then
+              opcode:=A_FDIV
+            else if opcode=A_FDIV then
+              opcode:=A_FDIVR
+            else if opcode=A_FSUBRP then
+              opcode:=A_FSUBP
+            else if opcode=A_FSUBP then
+              opcode:=A_FSUBRP
+            else if opcode=A_FDIVRP then
+              opcode:=A_FDIVP
+            else if opcode=A_FDIVP then
+              opcode:=A_FDIVRP;
+         if  ((ops=1) and
+            (oper[0].typ=top_reg) and
+            (oper[0].reg.enum in [R_ST1..R_ST7])) then
+            if opcode=A_FSUBRP then
+              opcode:=A_FSUBP
+            else if opcode=A_FSUBP then
+              opcode:=A_FSUBRP
+            else if opcode=A_FDIVRP then
+              opcode:=A_FDIVP
+            else if opcode=A_FDIVP then
+              opcode:=A_FDIVRP;
+      end;
+
+
+{*****************************************************************************
+                                Assembler
+*****************************************************************************}
+
+{$ifndef NOAG386BIN}
+
+    type
+      ea=packed record
+        sib_present : boolean;
+        bytes : byte;
+        size  : byte;
+        modrm : byte;
+        sib   : byte;
+      end;
+
+    procedure taicpu.create_ot;
+      {
+        this function will also fix some other fields which only needs to be once
+      }
+      var
+        i,l,relsize : longint;
+        nb,ni:boolean;
+      begin
+        if ops=0 then
+         exit;
+        { update oper[].ot field }
+        for i:=0 to ops-1 do
+         with oper[i] do
+          begin
+            case typ of
+              top_reg :
+                begin
+                  if reg.enum=R_INTREGISTER then
+                    case reg.number of
+                      NR_AL:
+                        ot:=OT_REG_AL;
+                      NR_AX:
+                        ot:=OT_REG_AX;
+                      NR_EAX:
+                        ot:=OT_REG_EAX;
+                      NR_CL:
+                        ot:=OT_REG_CL;
+                      NR_CX:
+                        ot:=OT_REG_CX;
+                      NR_ECX:
+                        ot:=OT_REG_ECX;
+                      NR_DX:
+                        ot:=OT_REG_DX;
+                      NR_CS:
+                        ot:=OT_REG_CS;
+                      NR_DS,NR_ES,NR_SS:
+                        ot:=OT_REG_DESS;
+                      NR_FS,NR_GS:
+                        ot:=OT_REG_FSGS;
+                      NR_DR0..NR_DR7:
+                        ot:=OT_REG_DREG;
+                      NR_CR0..NR_CR3:
+                        ot:=OT_REG_CREG;
+                      NR_CR4:
+                        ot:=OT_REG_CR4;
+                      NR_TR3..NR_TR7:
+                        ot:=OT_REG_TREG;
+                      else
+                        ot:=subreg2type[reg.number and $ff];
+                    end
+                  else
+                    ot:=reg2type[reg.enum];
+                end;
+              top_ref :
+                begin
+                  nb:=(ref^.base.enum=R_NO) or
+                     ((ref^.base.enum=R_INTREGISTER) and (ref^.base.number=NR_NO));
+                  ni:=(ref^.index.enum=R_NO) or
+                     ((ref^.index.enum=R_INTREGISTER) and (ref^.index.number=NR_NO));
+                { create ot field }
+                  if (ot and OT_SIZE_MASK)=0 then
+                    ot:=OT_MEMORY or opsize_2_type[i,opsize]
+                  else
+                    ot:=OT_MEMORY or (ot and OT_SIZE_MASK);
+                  if nb and ni then
+                    ot:=ot or OT_MEM_OFFS;
+                { fix scalefactor }
+                  if ni then
+                   ref^.scalefactor:=0
+                  else
+                   if (ref^.scalefactor=0) then
+                    ref^.scalefactor:=1;
+                end;
+              top_const :
+                begin
+                  if (opsize<>S_W) and (longint(val)>=-128) and (val<=127) then
+                    ot:=OT_IMM8 or OT_SIGNED
+                  else
+                    ot:=OT_IMMEDIATE or opsize_2_type[i,opsize];
+                end;
+              top_symbol :
+                begin
+                  if LastInsOffset=-1 then
+                   l:=0
+                  else
+                   l:=InsOffset-LastInsOffset;
+                  inc(l,symofs);
+                  if assigned(sym) then
+                   inc(l,sym.address);
+                  { instruction size will then always become 2 (PFV) }
+                  relsize:=(InsOffset+2)-l;
+                  if (not assigned(sym) or
+                      ((sym.currbind<>AB_EXTERNAL) and (sym.address<>0))) and
+                     (relsize>=-128) and (relsize<=127) then
+                   ot:=OT_IMM32 or OT_SHORT
+                  else
+                   ot:=OT_IMM32 or OT_NEAR;
+                end;
+            end;
+          end;
+      end;
+
+
+    function taicpu.InsEnd:longint;
+      begin
+        InsEnd:=InsOffset+InsSize;
+      end;
+
+
+      function taicpu.Matches(p:PInsEntry):longint;
+      { * IF_SM stands for Size Match: any operand whose size is not
+       * explicitly specified by the template is `really' intended to be
+       * the same size as the first size-specified operand.
+       * Non-specification is tolerated in the input instruction, but
+       * _wrong_ specification is not.
+       *
+       * IF_SM2 invokes Size Match on only the first _two_ operands, for
+       * three-operand instructions such as SHLD: it implies that the
+       * first two operands must match in size, but that the third is
+       * required to be _unspecified_.
+       *
+       * IF_SB invokes Size Byte: operands with unspecified size in the
+       * template are really bytes, and so no non-byte specification in
+       * the input instruction will be tolerated. IF_SW similarly invokes
+       * Size Word, and IF_SD invokes Size Doubleword.
+       *
+       * (The default state if neither IF_SM nor IF_SM2 is specified is
+       * that any operand with unspecified size in the template is
+       * required to have unspecified size in the instruction too...)
+      }
+      var
+        i,j,asize,oprs : longint;
+        siz : array[0..2] of longint;
+      begin
+        Matches:=100;
+
+        { Check the opcode and operands }
+        if (p^.opcode<>opcode) or (p^.ops<>ops) then
+         begin
+           Matches:=0;
+           exit;
+         end;
+
+        { Check that no spurious colons or TOs are present }
+        for i:=0 to p^.ops-1 do
+         if (oper[i].ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then
+          begin
+            Matches:=0;
+            exit;
+          end;
+
+        { Check that the operand flags all match up }
+        for i:=0 to p^.ops-1 do
+         begin
+           if ((p^.optypes[i] and (not oper[i].ot)) or
+               ((p^.optypes[i] and OT_SIZE_MASK) and
+                ((p^.optypes[i] xor oper[i].ot) and OT_SIZE_MASK)))<>0 then
+            begin
+              if ((p^.optypes[i] and (not oper[i].ot) and OT_NON_SIZE) or
+                  (oper[i].ot and OT_SIZE_MASK))<>0 then
+               begin
+                 Matches:=0;
+                 exit;
+               end
+              else
+               Matches:=1;
+            end;
+         end;
+
+      { Check operand sizes }
+        { as default an untyped size can get all the sizes, this is different
+          from nasm, but else we need to do a lot checking which opcodes want
+          size or not with the automatic size generation }
+        asize:=longint($ffffffff);
+        if (p^.flags and IF_SB)<>0 then
+          asize:=OT_BITS8
+        else if (p^.flags and IF_SW)<>0 then
+          asize:=OT_BITS16
+        else if (p^.flags and IF_SD)<>0 then
+          asize:=OT_BITS32;
+        if (p^.flags and IF_ARMASK)<>0 then
+         begin
+           siz[0]:=0;
+           siz[1]:=0;
+           siz[2]:=0;
+           if (p^.flags and IF_AR0)<>0 then
+            siz[0]:=asize
+           else if (p^.flags and IF_AR1)<>0 then
+            siz[1]:=asize
+           else if (p^.flags and IF_AR2)<>0 then
+            siz[2]:=asize;
+         end
+        else
+         begin
+         { we can leave because the size for all operands is forced to be
+           the same
+           but not if IF_SB IF_SW or IF_SD is set PM }
+           if asize=-1 then
+             exit;
+           siz[0]:=asize;
+           siz[1]:=asize;
+           siz[2]:=asize;
+         end;
+
+        if (p^.flags and (IF_SM or IF_SM2))<>0 then
+         begin
+           if (p^.flags and IF_SM2)<>0 then
+            oprs:=2
+           else
+            oprs:=p^.ops;
+           for i:=0 to oprs-1 do
+            if ((p^.optypes[i] and OT_SIZE_MASK) <> 0) then
+             begin
+               for j:=0 to oprs-1 do
+                siz[j]:=p^.optypes[i] and OT_SIZE_MASK;
+               break;
+             end;
+          end
+         else
+          oprs:=2;
+
+        { Check operand sizes }
+        for i:=0 to p^.ops-1 do
+         begin
+           if ((p^.optypes[i] and OT_SIZE_MASK)=0) and
+              ((oper[i].ot and OT_SIZE_MASK and (not siz[i]))<>0) and
+              { Immediates can always include smaller size }
+              ((oper[i].ot and OT_IMMEDIATE)=0) and
+               (((p^.optypes[i] and OT_SIZE_MASK) or siz[i])<(oper[i].ot and OT_SIZE_MASK)) then
+            Matches:=2;
+         end;
+      end;
+
+
+    procedure taicpu.ResetPass1;
+      begin
+        { we need to reset everything here, because the choosen insentry
+          can be invalid for a new situation where the previously optimized
+          insentry is not correct }
+        InsEntry:=nil;
+        InsSize:=0;
+        LastInsOffset:=-1;
+      end;
+
+
+    procedure taicpu.ResetPass2;
+      begin
+        { we are here in a second pass, check if the instruction can be optimized }
+        if assigned(InsEntry) and
+           ((InsEntry^.flags and IF_PASS2)<>0) then
+         begin
+           InsEntry:=nil;
+           InsSize:=0;
+         end;
+        LastInsOffset:=-1;
+      end;
+
+
+    function taicpu.CheckIfValid:boolean;
+      var
+        m,i : longint;
+      begin
+        CheckIfValid:=false;
+      { Things which may only be done once, not when a second pass is done to
+        optimize }
+        if (Insentry=nil) or ((InsEntry^.flags and IF_PASS2)<>0) then
+         begin
+           { We need intel style operands }
+           SetOperandOrder(op_intel);
+           { create the .ot fields }
+           create_ot;
+           { set the file postion }
+           aktfilepos:=fileinfo;
+         end
+        else
+         begin
+           { we've already an insentry so it's valid }
+           CheckIfValid:=true;
+           exit;
+         end;
+      { Lookup opcode in the table }
+        InsSize:=-1;
+        i:=instabcache^[opcode];
+        if i=-1 then
+         begin
+           Message1(asmw_e_opcode_not_in_table,gas_op2str[opcode]);
+           exit;
+         end;
+        insentry:=@instab[i];
+        while (insentry^.opcode=opcode) do
+         begin
+           m:=matches(insentry);
+           if m=100 then
+            begin
+              InsSize:=calcsize(insentry);
+              if not((segprefix.enum=R_NO) or ((segprefix.enum=R_INTREGISTER) and (segprefix.number=NR_NO))) then
+               inc(InsSize);
+              { For opsize if size if forced }
+              if (insentry^.flags and (IF_SB or IF_SW or IF_SD))<>0 then
+                 begin
+                   if (insentry^.flags and IF_ARMASK)=0 then
+                     begin
+                       if (insentry^.flags and IF_SB)<>0 then
+                         begin
+                           if opsize=S_NO then
+                             opsize:=S_B;
+                         end
+                       else if (insentry^.flags and IF_SW)<>0 then
+                         begin
+                           if opsize=S_NO then
+                             opsize:=S_W;
+                         end
+                       else if (insentry^.flags and IF_SD)<>0 then
+                         begin
+                           if opsize=S_NO then
+                             opsize:=S_L;
+                         end;
+                     end;
+                 end;
+              CheckIfValid:=true;
+              exit;
+            end;
+           inc(i);
+           insentry:=@instab[i];
+         end;
+        if insentry^.opcode<>opcode then
+         Message1(asmw_e_invalid_opcode_and_operands,GetString);
+      { No instruction found, set insentry to nil and inssize to -1 }
+        insentry:=nil;
+        inssize:=-1;
+      end;
+
+
+
+    function taicpu.Pass1(offset:longint):longint;
+      begin
+        Pass1:=0;
+      { Save the old offset and set the new offset }
+        InsOffset:=Offset;
+      { Things which may only be done once, not when a second pass is done to
+        optimize }
+        if Insentry=nil then
+         begin
+           { Check if error last time then InsSize=-1 }
+           if InsSize=-1 then
+            exit;
+           { set the file postion }
+           aktfilepos:=fileinfo;
+         end
+        else
+         begin
+{$ifdef PASS2FLAG}
+           { we are here in a second pass, check if the instruction can be optimized }
+           if (InsEntry^.flags and IF_PASS2)=0 then
+            begin
+              Pass1:=InsSize;
+              exit;
+            end;
+           { update the .ot fields, some top_const can be updated }
+           create_ot;
+{$endif PASS2FLAG}
+         end;
+      { Check if it's a valid instruction }
+        if CheckIfValid then
+         begin
+           LastInsOffset:=InsOffset;
+           Pass1:=InsSize;
+           exit;
+         end;
+        LastInsOffset:=-1;
+      end;
+
+
+    procedure taicpu.Pass2(sec:TAsmObjectData);
+      var
+        c : longint;
+      begin
+        { error in pass1 ? }
+        if insentry=nil then
+         exit;
+        aktfilepos:=fileinfo;
+        { Segment override }
+        if segprefix.enum>lastreg then
+          internalerror(200201081);
+        if (segprefix.enum<>R_NO) then
+         begin
+           case segprefix.enum of
+             R_CS : c:=$2e;
+             R_DS : c:=$3e;
+             R_ES : c:=$26;
+             R_FS : c:=$64;
+             R_GS : c:=$65;
+             R_SS : c:=$36;
+           end;
+           sec.writebytes(c,1);
+           { fix the offset for GenNode }
+           inc(InsOffset);
+         end;
+        { Generate the instruction }
+        GenCode(sec);
+      end;
+
+
+    function taicpu.needaddrprefix(opidx:byte):boolean;
+
+    var i,b:Tnewregister;
+        ia,ba:boolean;
+
+    begin
+      needaddrprefix:=false;
+      if (OT_MEMORY and (not oper[opidx].ot))=0 then
+        begin
+          if oper[opidx].ref^.index.enum=R_INTREGISTER then
+            begin
+              i:=oper[opidx].ref^.index.number;
+              ia:=(i<>NR_NO) and (i and $ff<>R_SUBD);
+            end
+          else
+            ia:=not(oper[opidx].ref^.index.enum in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]);
+          if oper[opidx].ref^.base.enum=R_INTREGISTER then
+            begin
+              b:=oper[opidx].ref^.base.number;
+              ba:=(b<>NR_NO) and (b and $ff<>R_SUBD);
+            end
+          else
+            ba:=not(oper[opidx].ref^.base.enum in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]);
+          b:=oper[opidx].ref^.base.number;
+          i:=oper[opidx].ref^.index.number;
+          if ia or ba then
+            needaddrprefix:=true;
+        end;
+    end;
+
+
+    function regval(r:tregister):byte;
+      begin
+        case r.enum of
+          R_EAX,R_AX,R_AL,R_ES,R_CR0,R_DR0,R_ST,R_ST0,R_MM0,R_XMM0 :
+            regval:=0;
+          R_ECX,R_CX,R_CL,R_CS,R_DR1,R_ST1,R_MM1,R_XMM1 :
+            regval:=1;
+          R_EDX,R_DX,R_DL,R_SS,R_CR2,R_DR2,R_ST2,R_MM2,R_XMM2 :
+            regval:=2;
+          R_EBX,R_BX,R_BL,R_DS,R_CR3,R_DR3,R_TR3,R_ST3,R_MM3,R_XMM3 :
+            regval:=3;
+          R_ESP,R_SP,R_AH,R_FS,R_CR4,R_TR4,R_ST4,R_MM4,R_XMM4 :
+            regval:=4;
+          R_EBP,R_BP,R_CH,R_GS,R_TR5,R_ST5,R_MM5,R_XMM5 :
+            regval:=5;
+          R_ESI,R_SI,R_DH,R_DR6,R_TR6,R_ST6,R_MM6,R_XMM6 :
+            regval:=6;
+          R_EDI,R_DI,R_BH,R_DR7,R_TR7,R_ST7,R_MM7,R_XMM7 :
+            regval:=7;
+          else
+            begin
+              internalerror(777001);
+              regval:=0;
+            end;
+        end;
+      end;
+
+
+    function process_ea(const input:toper;var output:ea;rfield:longint):boolean;
+      const
+        regs : array[0..63] of Toldregister=(
+          R_MM0, R_EAX, R_AX, R_AL, R_XMM0, R_NO, R_NO, R_NO,
+          R_MM1, R_ECX, R_CX, R_CL, R_XMM1, R_NO, R_NO, R_NO,
+          R_MM2, R_EDX, R_DX, R_DL, R_XMM2, R_NO, R_NO, R_NO,
+          R_MM3, R_EBX, R_BX, R_BL, R_XMM3, R_NO, R_NO, R_NO,
+          R_MM4, R_ESP, R_SP, R_AH, R_XMM4, R_NO, R_NO, R_NO,
+          R_MM5, R_EBP, R_BP, R_CH, R_XMM5, R_NO, R_NO, R_NO,
+          R_MM6, R_ESI, R_SI, R_DH, R_XMM6, R_NO, R_NO, R_NO,
+          R_MM7, R_EDI, R_DI, R_BH, R_XMM7, R_NO, R_NO, R_NO
+        );
+      var
+        j     : longint;
+        i,b   : Toldregister;
+        sym   : tasmsymbol;
+        md,s  : byte;
+        base,index,scalefactor,
+        o     : longint;
+        ireg  : Tregister;
+        ir,br : Tregister;
+      begin
+        process_ea:=false;
+      { register ? }
+        if (input.typ=top_reg) then
+         begin
+           ireg:=input.reg;
+           convert_register_to_enum(ireg);
+           j:=0;
+           while (j<=high(regs)) do
+            begin
+              if ireg.enum=regs[j] then
+               break;
+              inc(j);
+            end;
+           if j<=high(regs) then
+            begin
+              output.sib_present:=false;
+              output.bytes:=0;
+              output.modrm:=$c0 or (rfield shl 3) or (j shr 3);
+              output.size:=1;
+              process_ea:=true;
+            end;
+           exit;
+         end;
+      { memory reference }
+        ir:=input.ref^.index;
+        br:=input.ref^.base;
+        convert_register_to_enum(ir);
+        convert_register_to_enum(br);
+        i:=ir.enum;
+        b:=br.enum;
+        if (i>lastreg) or (b>lastreg) then
+          internalerror(200301081);
+        s:=input.ref^.scalefactor;
+        o:=input.ref^.offset+input.ref^.offsetfixup;
+        sym:=input.ref^.symbol;
+      { it's direct address }
+        if (b=R_NO) and (i=R_NO) then
+         begin
+           { it's a pure offset }
+           output.sib_present:=false;
+           output.bytes:=4;
+           output.modrm:=5 or (rfield shl 3);
+         end
+        else
+        { it's an indirection }
+         begin
+           { 16 bit address? }
+           if not((i in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) and
+                  (b in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI])) then
+            Message(asmw_e_16bit_not_supported);
+{$ifdef OPTEA}
+           { make single reg base }
+           if (b=R_NO) and (s=1) then
+            begin
+              b:=i;
+              i:=R_NO;
+            end;
+           { convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
+           if (b=R_NO) and
+              (((s=2) and (i<>R_ESP)) or
+                (s=3) or (s=5) or (s=9)) then
+            begin
+              b:=i;
+              dec(s);
+            end;
+           { swap ESP into base if scalefactor is 1 }
+           if (s=1) and (i=R_ESP) then
+            begin
+              i:=b;
+              b:=R_ESP;
+            end;
+{$endif OPTEA}
+           { wrong, for various reasons }
+           if (i=R_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (i<>R_NO)) then
+            exit;
+           { base }
+           case b of
+             R_EAX : base:=0;
+             R_ECX : base:=1;
+             R_EDX : base:=2;
+             R_EBX : base:=3;
+             R_ESP : base:=4;
+             R_NO,
+             R_EBP : base:=5;
+             R_ESI : base:=6;
+             R_EDI : base:=7;
+           else
+             exit;
+           end;
+           { index }
+           case i of
+             R_EAX : index:=0;
+             R_ECX : index:=1;
+             R_EDX : index:=2;
+             R_EBX : index:=3;
+             R_NO  : index:=4;
+             R_EBP : index:=5;
+             R_ESI : index:=6;
+             R_EDI : index:=7;
+           else
+             exit;
+           end;
+           case s of
+            0,
+            1 : scalefactor:=0;
+            2 : scalefactor:=1;
+            4 : scalefactor:=2;
+            8 : scalefactor:=3;
+           else
+            exit;
+           end;
+           if (b=R_NO) or
+              ((b<>R_EBP) and (o=0) and (sym=nil)) then
+            md:=0
+           else
+            if ((o>=-128) and (o<=127) and (sym=nil)) then
+             md:=1
+            else
+             md:=2;
+           if (b=R_NO) or (md=2) then
+            output.bytes:=4
+           else
+            output.bytes:=md;
+           { SIB needed ? }
+           if (i=R_NO) and (b<>R_ESP) then
+            begin
+              output.sib_present:=false;
+              output.modrm:=(md shl 6) or (rfield shl 3) or base;
+            end
+           else
+            begin
+              output.sib_present:=true;
+              output.modrm:=(md shl 6) or (rfield shl 3) or 4;
+              output.sib:=(scalefactor shl 6) or (index shl 3) or base;
+            end;
+         end;
+        if output.sib_present then
+         output.size:=2+output.bytes
+        else
+         output.size:=1+output.bytes;
+        process_ea:=true;
+      end;
+
+
+    function taicpu.calcsize(p:PInsEntry):longint;
+      var
+        codes : pchar;
+        c     : byte;
+        len     : longint;
+        ea_data : ea;
+      begin
+        len:=0;
+        codes:=@p^.code;
+        repeat
+          c:=ord(codes^);
+          inc(codes);
+          case c of
+            0 :
+              break;
+            1,2,3 :
+              begin
+                inc(codes,c);
+                inc(len,c);
+              end;
+            8,9,10 :
+              begin
+                inc(codes);
+                inc(len);
+              end;
+            4,5,6,7 :
+              begin
+                if opsize=S_W then
+                  inc(len,2)
+                else
+                  inc(len);
+              end;
+            15,
+            12,13,14,
+            16,17,18,
+            20,21,22,
+            40,41,42 :
+              inc(len);
+            24,25,26,
+            31,
+            48,49,50 :
+              inc(len,2);
+            28,29,30, { we don't have 16 bit immediates code }
+            32,33,34,
+            52,53,54,
+            56,57,58 :
+              inc(len,4);
+            192,193,194 :
+              if NeedAddrPrefix(c-192) then
+               inc(len);
+            208 :
+              inc(len);
+            200,
+            201,
+            202,
+            209,
+            210,
+            217,218,219 : ;
+            216 :
+              begin
+                inc(codes);
+                inc(len);
+              end;
+            224,225,226 :
+              begin
+                InternalError(777002);
+              end;
+            else
+              begin
+                if (c>=64) and (c<=191) then
+                 begin
+                   if not process_ea(oper[(c shr 3) and 7], ea_data, 0) then
+                    Message(asmw_e_invalid_effective_address)
+                   else
+                    inc(len,ea_data.size);
+                 end
+                else
+                 InternalError(777003);
+              end;
+          end;
+        until false;
+        calcsize:=len;
+      end;
+
+
+    procedure taicpu.GenCode(sec:TAsmObjectData);
+      {
+       * the actual codes (C syntax, i.e. octal):
+       * \0            - terminates the code. (Unless it's a literal of course.)
+       * \1, \2, \3    - that many literal bytes follow in the code stream
+       * \4, \6        - the POP/PUSH (respectively) codes for CS, DS, ES, SS
+       *                 (POP is never used for CS) depending on operand 0
+       * \5, \7        - the second byte of POP/PUSH codes for FS, GS, depending
+       *                 on operand 0
+       * \10, \11, \12 - a literal byte follows in the code stream, to be added
+       *                 to the register value of operand 0, 1 or 2
+       * \17           - encodes the literal byte 0. (Some compilers don't take
+       *                 kindly to a zero byte in the _middle_ of a compile time
+       *                 string constant, so I had to put this hack in.)
+       * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2
+       * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2
+       * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2
+       * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2
+       * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit
+       *                 assembly mode or the address-size override on the operand
+       * \37           - a word constant, from the _segment_ part of operand 0
+       * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2
+       * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2
+       * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2
+       * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit
+       *                 assembly mode or the address-size override on the operand
+       * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2
+       * \1ab          - a ModRM, calculated on EA in operand a, with the spare
+       *                 field the register value of operand b.
+       * \2ab          - a ModRM, calculated on EA in operand a, with the spare
+       *                 field equal to digit b.
+       * \30x          - might be an 0x67 byte, depending on the address size of
+       *                 the memory reference in operand x.
+       * \310          - indicates fixed 16-bit address size, i.e. optional 0x67.
+       * \311          - indicates fixed 32-bit address size, i.e. optional 0x67.
+       * \320          - indicates fixed 16-bit operand size, i.e. optional 0x66.
+       * \321          - indicates fixed 32-bit operand size, i.e. optional 0x66.
+       * \322          - indicates that this instruction is only valid when the
+       *                 operand size is the default (instruction to disassembler,
+       *                 generates no code in the assembler)
+       * \330          - a literal byte follows in the code stream, to be added
+       *                 to the condition code value of the instruction.
+       * \340          - reserve <operand 0> bytes of uninitialised storage.
+       *                 Operand 0 had better be a segmentless constant.
+      }
+
+      var
+        currval : longint;
+        currsym : tasmsymbol;
+
+        procedure getvalsym(opidx:longint);
+        begin
+          case oper[opidx].typ of
+            top_ref :
+              begin
+                currval:=oper[opidx].ref^.offset+oper[opidx].ref^.offsetfixup;
+                currsym:=oper[opidx].ref^.symbol;
+              end;
+            top_const :
+              begin
+                currval:=longint(oper[opidx].val);
+                currsym:=nil;
+              end;
+            top_symbol :
+              begin
+                currval:=oper[opidx].symofs;
+                currsym:=oper[opidx].sym;
+              end;
+            else
+              Message(asmw_e_immediate_or_reference_expected);
+          end;
+        end;
+
+      const
+        CondVal:array[TAsmCond] of byte=($0,
+         $7, $3, $2, $6, $2, $4, $F, $D, $C, $E, $6, $2,
+         $3, $7, $3, $5, $E, $C, $D, $F, $1, $B, $9, $5,
+         $0, $A, $A, $B, $8, $4);
+      var
+        c : byte;
+        pb,
+        codes : pchar;
+        bytes : array[0..3] of byte;
+        rfield,
+        data,s,opidx : longint;
+        ea_data : ea;
+      begin
+{$ifdef EXTDEBUG}
+        { safety check }
+        if sec.sects[sec.currsec].datasize<>insoffset then
+         internalerror(200130121);
+{$endif EXTDEBUG}
+        { load data to write }
+        codes:=insentry^.code;
+        { Force word push/pop for registers }
+        if (opsize=S_W) and ((codes[0]=#4) or (codes[0]=#6) or
+            ((codes[0]=#1) and ((codes[2]=#5) or (codes[2]=#7)))) then
+          begin
+            bytes[0]:=$66;
+            sec.writebytes(bytes,1);
+          end;
+        repeat
+          c:=ord(codes^);
+          inc(codes);
+          case c of
+            0 :
+              break;
+            1,2,3 :
+              begin
+                sec.writebytes(codes^,c);
+                inc(codes,c);
+              end;
+            4,6 :
+              begin
+                case oper[0].reg.enum of
+                  R_CS :
+                    begin
+                      if c=4 then
+                       bytes[0]:=$f
+                      else
+                       bytes[0]:=$e;
+                    end;
+                  R_NO,
+                  R_DS :
+                    begin
+                      if c=4 then
+                       bytes[0]:=$1f
+                      else
+                       bytes[0]:=$1e;
+                    end;
+                  R_ES :
+                    begin
+                      if c=4 then
+                       bytes[0]:=$7
+                      else
+                       bytes[0]:=$6;
+                    end;
+                  R_SS :
+                    begin
+                      if c=4 then
+                       bytes[0]:=$17
+                      else
+                       bytes[0]:=$16;
+                    end;
+                  else
+                    InternalError(777004);
+                end;
+                sec.writebytes(bytes,1);
+              end;
+            5,7 :
+              begin
+                case oper[0].reg.enum of
+                  R_FS :
+                    begin
+                      if c=5 then
+                       bytes[0]:=$a1
+                      else
+                       bytes[0]:=$a0;
+                    end;
+                  R_GS :
+                    begin
+                      if c=5 then
+                       bytes[0]:=$a9
+                      else
+                       bytes[0]:=$a8;
+                    end;
+                  else
+                    InternalError(777005);
+                end;
+                sec.writebytes(bytes,1);
+              end;
+            8,9,10 :
+              begin
+                bytes[0]:=ord(codes^)+regval(oper[c-8].reg);
+                inc(codes);
+                sec.writebytes(bytes,1);
+              end;
+            15 :
+              begin
+                bytes[0]:=0;
+                sec.writebytes(bytes,1);
+              end;
+            12,13,14 :
+              begin
+                getvalsym(c-12);
+                if (currval<-128) or (currval>127) then
+                 Message2(asmw_e_value_exceeds_bounds,'signed byte',tostr(currval));
+                if assigned(currsym) then
+                  sec.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
+                else
+                  sec.writebytes(currval,1);
+              end;
+            16,17,18 :
+              begin
+                getvalsym(c-16);
+                if (currval<-256) or (currval>255) then
+                 Message2(asmw_e_value_exceeds_bounds,'byte',tostr(currval));
+                if assigned(currsym) then
+                 sec.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
+                else
+                 sec.writebytes(currval,1);
+              end;
+            20,21,22 :
+              begin
+                getvalsym(c-20);
+                if (currval<0) or (currval>255) then
+                 Message2(asmw_e_value_exceeds_bounds,'unsigned byte',tostr(currval));
+                if assigned(currsym) then
+                 sec.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
+                else
+                 sec.writebytes(currval,1);
+              end;
+            24,25,26 :
+              begin
+                getvalsym(c-24);
+                if (currval<-65536) or (currval>65535) then
+                 Message2(asmw_e_value_exceeds_bounds,'word',tostr(currval));
+                if assigned(currsym) then
+                 sec.writereloc(currval,2,currsym,RELOC_ABSOLUTE)
+                else
+                 sec.writebytes(currval,2);
+              end;
+            28,29,30 :
+              begin
+                getvalsym(c-28);
+                if assigned(currsym) then
+                 sec.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
+                else
+                 sec.writebytes(currval,4);
+              end;
+            32,33,34 :
+              begin
+                getvalsym(c-32);
+                if assigned(currsym) then
+                 sec.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
+                else
+                 sec.writebytes(currval,4);
+              end;
+            40,41,42 :
+              begin
+                getvalsym(c-40);
+                data:=currval-insend;
+                if assigned(currsym) then
+                 inc(data,currsym.address);
+                if (data>127) or (data<-128) then
+                 Message1(asmw_e_short_jmp_out_of_range,tostr(data));
+                sec.writebytes(data,1);
+              end;
+            52,53,54 :
+              begin
+                getvalsym(c-52);
+                if assigned(currsym) then
+                 sec.writereloc(currval,4,currsym,RELOC_RELATIVE)
+                else
+                 sec.writereloc(currval-insend,4,nil,RELOC_ABSOLUTE)
+              end;
+            56,57,58 :
+              begin
+                getvalsym(c-56);
+                if assigned(currsym) then
+                 sec.writereloc(currval,4,currsym,RELOC_RELATIVE)
+                else
+                 sec.writereloc(currval-insend,4,nil,RELOC_ABSOLUTE)
+              end;
+            192,193,194 :
+              begin
+                if NeedAddrPrefix(c-192) then
+                 begin
+                   bytes[0]:=$67;
+                   sec.writebytes(bytes,1);
+                 end;
+              end;
+            200 :
+              begin
+                bytes[0]:=$67;
+                sec.writebytes(bytes,1);
+              end;
+            208 :
+              begin
+                bytes[0]:=$66;
+                sec.writebytes(bytes,1);
+              end;
+            216 :
+              begin
+                bytes[0]:=ord(codes^)+condval[condition];
+                inc(codes);
+                sec.writebytes(bytes,1);
+              end;
+            201,
+            202,
+            209,
+            210,
+            217,218,219 :
+              begin
+                { these are dissambler hints or 32 bit prefixes which
+                  are not needed }
+              end;
+            31,
+            48,49,50,
+            224,225,226 :
+              begin
+                InternalError(777006);
+              end
+            else
+              begin
+                if (c>=64) and (c<=191) then
+                 begin
+                   if (c<127) then
+                    begin
+                      if (oper[c and 7].typ=top_reg) then
+                        rfield:=regval(oper[c and 7].reg)
+                      else
+                        rfield:=regval(oper[c and 7].ref^.base);
+                    end
+                   else
+                    rfield:=c and 7;
+                   opidx:=(c shr 3) and 7;
+                   if not process_ea(oper[opidx], ea_data, rfield) then
+                    Message(asmw_e_invalid_effective_address);
+
+                   pb:=@bytes;
+                   pb^:=chr(ea_data.modrm);
+                   inc(pb);
+                   if ea_data.sib_present then
+                    begin
+                      pb^:=chr(ea_data.sib);
+                      inc(pb);
+                    end;
+
+                   s:=pb-pchar(@bytes);
+                   sec.writebytes(bytes,s);
+
+                   case ea_data.bytes of
+                     0 : ;
+                     1 :
+                       begin
+                         if (oper[opidx].ot and OT_MEMORY)=OT_MEMORY then
+                          sec.writereloc(oper[opidx].ref^.offset+oper[opidx].ref^.offsetfixup,1,oper[opidx].ref^.symbol,RELOC_ABSOLUTE)
+                         else
+                          begin
+                            bytes[0]:=oper[opidx].ref^.offset+oper[opidx].ref^.offsetfixup;
+                            sec.writebytes(bytes,1);
+                          end;
+                         inc(s);
+                       end;
+                     2,4 :
+                       begin
+                         sec.writereloc(oper[opidx].ref^.offset+oper[opidx].ref^.offsetfixup,ea_data.bytes,
+                           oper[opidx].ref^.symbol,RELOC_ABSOLUTE);
+                         inc(s,ea_data.bytes);
+                       end;
+                   end;
+                 end
+                else
+                 InternalError(777007);
+              end;
+          end;
+        until false;
+      end;
+{$endif NOAG386BIN}
+
+    function Taicpu.is_nop:boolean;
+
+    begin
+      {We do not check the number of operands; we assume that nobody constructs
+       a mov or xchg instruction with less than 2 operands.}
+      is_nop:=(opcode=A_NOP) or
+              (opcode=A_MOV) and (oper[0].typ=top_reg) and (oper[1].typ=top_reg) and (oper[0].reg.number=oper[1].reg.number) or
+              (opcode=A_XCHG) and (oper[0].typ=top_reg) and (oper[1].typ=top_reg) and (oper[0].reg.number=oper[1].reg.number);
+    end;
+
+
+{*****************************************************************************
+                              Instruction table
+*****************************************************************************}
+
+    procedure BuildInsTabCache;
+{$ifndef NOAG386BIN}
+      var
+        i : longint;
+{$endif}
+      begin
+{$ifndef NOAG386BIN}
+        new(instabcache);
+        FillChar(instabcache^,sizeof(tinstabcache),$ff);
+        i:=0;
+        while (i<InsTabEntries) do
+         begin
+           if InsTabCache^[InsTab[i].OPcode]=-1 then
+            InsTabCache^[InsTab[i].OPcode]:=i;
+           inc(i);
+         end;
+{$endif NOAG386BIN}
+      end;
+
+
+    procedure InitAsm;
+      begin
+{$ifndef NOAG386BIN}
+        if not assigned(instabcache) then
+          BuildInsTabCache;
+{$endif NOAG386BIN}
+      end;
+
+
+    procedure DoneAsm;
+      begin
+{$ifndef NOAG386BIN}
+        if assigned(instabcache) then
+        begin
+          dispose(instabcache);
+          instabcache:=nil;
+        end;
+{$endif NOAG386BIN}
+      end;
+
+
+
+end.
+{
+  $Log$
+  Revision 1.2  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.1  2003/04/25 12:43:40  florian
+    * merged i386/aasmcpu and x86_64/aasmcpu to x86/aasmcpu
+
+  Revision 1.18  2003/04/25 12:04:31  florian
+    * merged agx64att and ag386att to x86/agx86att
+
+  Revision 1.17  2003/04/22 14:33:38  peter
+    * removed some notes/hints
+
+  Revision 1.16  2003/04/22 10:09:35  daniel
+    + Implemented the actual register allocator
+    + Scratch registers unavailable when new register allocator used
+    + maybe_save/maybe_restore unavailable when new register allocator used
+
+  Revision 1.15  2003/03/26 12:50:54  armin
+  * avoid problems with the ide in init/dome
+
+  Revision 1.14  2003/03/08 08:59:07  daniel
+    + $define newra will enable new register allocator
+    + getregisterint will return imaginary registers with $newra
+    + -sr switch added, will skip register allocation so you can see
+      the direct output of the code generator before register allocation
+
+  Revision 1.13  2003/02/25 07:41:54  daniel
+    * Properly fixed reversed operands bug
+
+  Revision 1.12  2003/02/19 22:00:15  daniel
+    * Code generator converted to new register notation
+    - Horribily outdated todo.txt removed
+
+  Revision 1.11  2003/01/09 20:40:59  daniel
+    * Converted some code in cgx86.pas to new register numbering
+
+  Revision 1.10  2003/01/08 18:43:57  daniel
+   * Tregister changed into a record
+
+  Revision 1.9  2003/01/05 13:36:53  florian
+    * x86-64 compiles
+    + very basic support for float128 type (x86-64 only)
+
+  Revision 1.8  2002/11/17 16:31:58  carl
+    * memory optimization (3-4%) : cleanup of tai fields,
+       cleanup of tdef and tsym fields.
+    * make it work for m68k
+
+  Revision 1.7  2002/11/15 01:58:54  peter
+    * merged changes from 1.0.7 up to 04-11
+      - -V option for generating bug report tracing
+      - more tracing for option parsing
+      - errors for cdecl and high()
+      - win32 import stabs
+      - win32 records<=8 are returned in eax:edx (turned off by default)
+      - heaptrc update
+      - more info for temp management in .s file with EXTDEBUG
+
+  Revision 1.6  2002/10/31 13:28:32  pierre
+   * correct last wrong fix for tw2158
+
+  Revision 1.5  2002/10/30 17:10:00  pierre
+   * merge of fix for tw2158 bug
+
+  Revision 1.4  2002/08/15 19:10:36  peter
+    * first things tai,tnode storing in ppu
+
+  Revision 1.3  2002/08/13 18:01:52  carl
+    * rename swatoperands to swapoperands
+    + m68k first compilable version (still needs a lot of testing):
+        assembler generator, system information , inline
+        assembler reader.
+
+  Revision 1.2  2002/07/20 11:57:59  florian
+    * types.pas renamed to defbase.pas because D6 contains a types
+      unit so this would conflicts if D6 programms are compiled
+    + Willamette/SSE2 instructions to assembler added
+
+  Revision 1.1  2002/07/01 18:46:29  peter
+    * internal linker
+    * reorganized aasm layer
+
+}

+ 911 - 0
compiler/x86/cpubase.pas

@@ -0,0 +1,911 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
+
+    Contains the base types for the i386 and x86-64 architecture
+
+    * This code was inspired by the NASM sources
+      The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
+      Julian Hall. All rights reserved.
+
+    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.
+
+ ****************************************************************************
+}
+{# Base unit for processor information. This unit contains
+   enumerations of registers, opcodes, sizes, and other
+   such things which are processor specific.
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  cutils,cclasses,
+  globtype,globals,
+  cpuinfo,
+  aasmbase,
+  cginfo
+{$ifdef delphi}
+  ,dmisc
+{$endif}
+  ;
+
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+{$ifdef x86_64}
+      TAsmOp={$i x86_64op.inc}
+{$else x86_64}
+      TAsmOp={$i i386op.inc}
+{$endif x86_64}
+
+      {# This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[11];
+
+    const
+      {# First value of opcode enumeration }
+      firstop = low(tasmop);
+      {# Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+   type
+      { don't change the order }
+      { it's used by the register size conversions }
+      { Enumeration of all registers of the CPU }
+      toldregister = (R_NO,
+{$ifdef x86_64}
+        R_RAX,R_RCX,R_RDX,R_RBX,R_RSP,R_RBP,R_RSI,R_RDI,
+        R_R8,R_R9,R_R10,R_R11,R_R12,R_R13,R_R14,R_R15,R_RIP,
+{$endif x86_64}
+        R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
+{$ifdef x86_64}
+        R_R8D,R_R9D,R_R10D,R_R11D,R_R12D,R_R13D,R_R14D,R_R15D,
+{$endif x86_64}
+        R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
+{$ifdef x86_64}
+        R_R8W,R_R9W,R_R10W,R_R11W,R_R12W,R_R13W,R_R14W,R_R15W,
+{$endif x86_64}
+        R_AL,R_CL,R_DL,R_BL,
+{$ifdef x86_64}
+        R_SPL,R_BPL,R_SIL,R_DIL,
+        R_R8B,R_R9B,R_R10B,R_R11B,R_R12B,R_R13B,R_R14B,R_R15B,
+{$endif x86_64}
+        R_AH,R_CH,R_BH,R_DH,
+        R_CS,R_DS,R_ES,R_SS,R_FS,R_GS,
+        R_ST,R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7,
+        R_DR0,R_DR1,R_DR2,R_DR3,R_DR6,R_DR7,
+        R_CR0,R_CR2,R_CR3,R_CR4,
+        R_TR3,R_TR4,R_TR5,R_TR6,R_TR7,
+        R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7,
+        R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7,
+{$ifdef x86_64}
+        R_XMM8,R_XMM9,R_XMM10,R_XMM11,R_XMM12,R_XMM13,R_XMM14,R_XMM15,
+{$endif x86_64}
+        R_INTREGISTER,R_FLOATREGISTER,R_MMXREGISTER,R_KNIREGISTER
+      );
+
+      { The new register coding:
+
+        For now we'll use this, when the old register coding is away, we
+        can change this into a cardinal or something so the amount of
+        possible registers increases.
+
+        High byte: Register number
+        Low byte:  Subregister
+
+        Example:
+
+        $0100      AL
+        $0101      AH
+        $0102      AX
+        $0103      EAX
+        $0104      RAX
+        $0201      BL
+        $0203      EBX
+      }
+
+      {Super register numbers:}
+   const
+{$ifdef x86_64}
+      RS_SPECIAL    = $00;      {Special register}
+      RS_RAX        = $01;      {EAX}
+      RS_RBX        = $02;      {EBX}
+      RS_RCX        = $03;      {ECX}
+      RS_RDX        = $04;      {EDX}
+      RS_RSI        = $05;      {ESI}
+      RS_RDI        = $06;      {EDI}
+      RS_RBP        = $07;      {EBP}
+      RS_RSP        = $08;      {ESP}
+      RS_R8         = $09;      {R8}
+      RS_R9         = $0a;      {R9}
+      RS_R10        = $0b;      {R10}
+      RS_R11        = $0c;      {R11}
+      RS_R12        = $0d;      {R12}
+      RS_R13        = $0e;      {R13}
+      RS_R14        = $0f;      {R14}
+      RS_R15        = $10;      {R15}
+{$else x86_64}
+      RS_SPECIAL    = $00;      {Special register}
+      RS_EAX        = $01;      {EAX}
+      RS_EBX        = $02;      {EBX}
+      RS_ECX        = $03;      {ECX}
+      RS_EDX        = $04;      {EDX}
+      RS_ESI        = $05;      {ESI}
+      RS_EDI        = $06;      {EDI}
+      RS_EBP        = $07;      {EBP}
+      RS_ESP        = $08;      {ESP}
+{$endif x86_64}
+
+
+      {Number of first and last superregister.}
+      first_supreg    = $01;
+      last_supreg     = $10;
+      {Number of first and last imaginary register.}
+      first_imreg     = $12;
+      last_imreg      = $ff;
+
+      {Sub register numbers:}
+      R_SUBL        = $00;      {Like AL}
+      R_SUBH        = $01;      {Like AH}
+      R_SUBW        = $02;      {Like AX}
+      R_SUBD        = $03;      {Like EAX}
+      R_SUBQ        = $04;      {Like RAX}
+
+    {The subregister that specifies the entire register.}
+{$ifdef x86_64}
+      R_SUBWHOLE    = R_SUBQ; {Hammer}
+{$else x86_64}
+      R_SUBWHOLE    = R_SUBD;  {i386}
+{$endif x86_64}
+
+      { special registers }
+      NR_NO    = $0000;      {Invalid register}
+      NR_CS    = $0001;      {CS}
+      NR_DS    = $0002;      {DS}
+      NR_ES    = $0003;      {ES}
+      NR_SS    = $0004;      {SS}
+      NR_FS    = $0005;      {FS}
+      NR_GS    = $0006;      {GS}
+      NR_RIP   = $000F;      {RIP}
+      NR_DR0   = $0010;      {DR0}
+      NR_DR1   = $0011;      {DR1}
+      NR_DR2   = $0012;      {DR2}
+      NR_DR3   = $0013;      {DR3}
+      NR_DR6   = $0016;      {DR6}
+      NR_DR7   = $0017;      {DR7}
+      NR_CR0   = $0020;      {CR0}
+      NR_CR2   = $0021;      {CR1}
+      NR_CR3   = $0022;      {CR2}
+      NR_CR4   = $0023;      {CR3}
+      NR_TR3   = $0030;      {R_TR3}
+      NR_TR4   = $0031;      {R_TR4}
+      NR_TR5   = $0032;      {R_TR5}
+      NR_TR6   = $0033;      {R_TR6}
+      NR_TR7   = $0034;      {R_TR7}
+
+      { normal registers: }
+      NR_AL    = $0100;      {AL}
+      NR_AH    = $0101;      {AH}
+      NR_AX    = $0102;      {AX}
+      NR_EAX   = $0103;      {EAX}
+      NR_RAX   = $0104;      {RAX}
+      NR_BL    = $0200;      {BL}
+      NR_BH    = $0201;      {BH}
+      NR_BX    = $0202;      {BX}
+      NR_EBX   = $0203;      {EBX}
+      NR_RBX   = $0204;      {RBX}
+      NR_CL    = $0300;      {CL}
+      NR_CH    = $0301;      {CH}
+      NR_CX    = $0302;      {CX}
+      NR_ECX   = $0303;      {ECX}
+      NR_RCX   = $0304;      {RCX}
+      NR_DL    = $0400;      {DL}
+      NR_DH    = $0401;      {DH}
+      NR_DX    = $0402;      {DX}
+      NR_EDX   = $0403;      {EDX}
+      NR_RDX   = $0404;      {RDX}
+      NR_SIL   = $0500;      {SIL}
+      NR_SI    = $0502;      {SI}
+      NR_ESI   = $0503;      {ESI}
+      NR_RSI   = $0504;      {RSI}
+      NR_DIL   = $0600;      {DIL}
+      NR_DI    = $0602;      {DI}
+      NR_EDI   = $0603;      {EDI}
+      NR_RDI   = $0604;      {RDI}
+      NR_BPL   = $0700;      {BPL}
+      NR_BP    = $0702;      {BP}
+      NR_EBP   = $0703;      {EBP}
+      NR_RBP   = $0704;      {RBP}
+      NR_SPL   = $0800;      {SPL}
+      NR_SP    = $0802;      {SP}
+      NR_ESP   = $0803;      {ESP}
+      NR_RSP   = $0804;      {RSP}
+      NR_R8L   = $0900;      {R8L}
+      NR_R8W   = $0902;      {R8W}
+      NR_R8D   = $0903;      {R8D}
+      NR_R9L   = $0a00;      {R9D}
+      NR_R9W   = $0a02;      {R9W}
+      NR_R9D   = $0a03;      {R9D}
+      NR_R10L  = $0b00;      {R10L}
+      NR_R10W  = $0b02;      {R10W}
+      NR_R10D  = $0b03;      {R10D}
+      NR_R11L  = $0c00;      {R11L}
+      NR_R11W  = $0c02;      {R11W}
+      NR_R11D  = $0c03;      {R11D}
+      NR_R12L  = $0d00;      {R12L}
+      NR_R12W  = $0d02;      {R12W}
+      NR_R12D  = $0d03;      {R12D}
+      NR_R13L  = $0e00;      {R13L}
+      NR_R13W  = $0e02;      {R13W}
+      NR_R13D  = $0e03;      {R13D}
+      NR_R14L  = $0f00;      {R14L}
+      NR_R14W  = $0f02;      {R14W}
+      NR_R14D  = $0f03;      {R14D}
+      NR_R15L  = $1000;      {R15L}
+      NR_R15W  = $1002;      {R15W}
+      NR_R15D  = $1003;      {R15D}
+
+   type
+      tnewregister=word;
+
+      Tregister = packed record
+        enum:Toldregister;
+        number:Tnewregister;  {This is a word for now, change to cardinal
+                               when the old register coding is away.}
+      end;
+
+      Tsuperregister=byte;
+      Tsubregister=byte;
+
+      { A type to store register locations for 64 Bit values. }
+{$ifdef x86_64}
+      tregister64 = tregister;
+{$else x86_64}
+      tregister64 = packed record
+         reglo,reghi : tregister;
+      end;
+{$endif x86_64}
+
+      { alias for compact code }
+      treg64 = tregister64;
+
+      {# Set type definition for registers }
+      tregisterset = set of toldregister;
+      tsupregset = set of tsuperregister;
+
+
+    const
+      {# First register in the tregister enumeration }
+      firstreg = low(toldregister);
+{$ifdef x86_64}
+      { Last register in the tregister enumeration }
+      lastreg  = R_XMM15;
+{$else x86_64}
+      { Last register in the tregister enumeration }
+      lastreg  = R_XMM7;
+{$endif x86_64}
+
+      firstsreg = R_CS;
+      lastsreg  = R_GS;
+
+      nfirstsreg = NR_CS;
+      nlastsreg  = NR_GS;
+
+      regset8bit  : tregisterset = [R_AL..R_DH];
+      regset16bit : tregisterset = [R_AX..R_DI,R_CS..R_SS];
+      regset32bit : tregisterset = [R_EAX..R_EDI];
+
+    type
+      {# Type definition for the array of string of register names }
+         reg2strtable = array[firstreg..lastreg] of string[6];
+         regname2regnumrec = record
+           name:string[6];
+           number:Tnewregister;
+         end;
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond=(C_None,
+        C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
+        C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
+        C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
+      );
+
+    const
+      cond2str:array[TAsmCond] of string[3]=('',
+        'a','ae','b','be','c','e','g','ge','l','le','na','nae',
+        'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
+        'ns','nz','o','p','pe','po','s','z'
+      );
+
+      inverse_cond:array[TAsmCond] of TAsmCond=(C_None,
+        C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
+        C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
+        C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
+      );
+
+{*****************************************************************************
+                                   Flags
+*****************************************************************************}
+
+    type
+      TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,F_A,F_AE,F_B,F_BE);
+
+{*****************************************************************************
+                                Reference
+*****************************************************************************}
+
+    type
+      trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup);
+
+      { reference record }
+      preference = ^treference;
+      treference = packed record
+         segment,
+         base,
+         index       : tregister;
+         scalefactor : byte;
+         offset      : longint;
+         symbol      : tasmsymbol;
+         offsetfixup : longint;
+         options     : trefoptions;
+      end;
+
+      { reference record }
+      pparareference = ^tparareference;
+      tparareference = packed record
+         index       : tregister;
+         offset      : longint;
+      end;
+
+{*****************************************************************************
+                                Operands
+*****************************************************************************}
+
+      { Types of operand }
+      toptype=(top_none,top_reg,top_ref,top_const,top_symbol);
+
+      toper=record
+        ot  : longint;
+        case typ : toptype of
+         top_none   : ();
+         top_reg    : (reg:tregister);
+         top_ref    : (ref:preference);
+         top_const  : (val:aword);
+         top_symbol : (sym:tasmsymbol;symofs:longint);
+      end;
+
+{*****************************************************************************
+                               Generic Location
+*****************************************************************************}
+
+    type
+      { tparamlocation describes where a parameter for a procedure is stored.
+        References are given from the caller's point of view. The usual
+        TLocation isn't used, because contains a lot of unnessary fields.
+      }
+      tparalocation = packed record
+         size : TCGSize;
+         loc  : TCGLoc;
+         sp_fixup : longint;
+         case TCGLoc of
+            LOC_REFERENCE : (reference : tparareference);
+            { segment in reference at the same place as in loc_register }
+            LOC_REGISTER,LOC_CREGISTER : (
+              case longint of
+                1 : (register,registerhigh : tregister);
+                { overlay a registerlow }
+                2 : (registerlow : tregister);
+                { overlay a 64 Bit register type }
+                3 : (reg64 : tregister64);
+                4 : (register64 : tregister64);
+              );
+            { it's only for better handling }
+            LOC_MMXREGISTER,LOC_CMMXREGISTER : (mmxreg : tregister);
+      end;
+
+      tlocation = packed record
+         loc  : TCGLoc;
+         size : TCGSize;
+         case TCGLoc of
+            LOC_FLAGS : (resflags : tresflags);
+            LOC_CONSTANT : (
+              case longint of
+                1 : (value : AWord);
+                { can't do this, this layout depends on the host cpu. Use }
+                { lo(valueqword)/hi(valueqword) instead (JM)              }
+                { 2 : (valuelow, valuehigh:AWord);                        }
+                { overlay a complete 64 Bit value }
+                3 : (valueqword : qword);
+              );
+            LOC_CREFERENCE,
+            LOC_REFERENCE : (reference : treference);
+            { segment in reference at the same place as in loc_register }
+            LOC_REGISTER,LOC_CREGISTER : (
+              case longint of
+                1 : (register,registerhigh,segment : tregister);
+                { overlay a registerlow }
+                2 : (registerlow : tregister);
+                { overlay a 64 Bit register type }
+                3 : (reg64 : tregister64);
+                4 : (register64 : tregister64);
+              );
+            { it's only for better handling }
+            LOC_MMXREGISTER,LOC_CMMXREGISTER : (mmxreg : tregister);
+      end;
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      { declare aliases }
+      LOC_MMREGISTER = LOC_SSEREGISTER;
+      LOC_CMMREGISTER = LOC_CSSEREGISTER;
+
+      max_operands = 3;
+
+      lvaluelocations = [LOC_REFERENCE,LOC_CFPUREGISTER,
+        LOC_CREGISTER,LOC_MMXREGISTER,LOC_CMMXREGISTER];
+
+      {# Constant defining possibly all registers which might require saving }
+      ALL_REGISTERS = [firstreg..lastreg];
+      ALL_INTREGISTERS = [1..255];
+
+      {# low and high of the available maximum width integer general purpose }
+      { registers                                                            }
+      LoGPReg = R_EAX;
+      HiGPReg = R_EDX;
+
+      {# low and high of every possible width general purpose register (same as }
+      { above on most architctures apart from the 80x86)                        }
+      LoReg = R_EAX;
+      HiReg = R_DH;
+
+      {# Table of registers which can be allocated by the code generator
+         internally, when generating the code.
+      }
+      { legend:                                                                }
+      { xxxregs = set of all possibly used registers of that type in the code  }
+      {           generator                                                    }
+      { usableregsxxx = set of all 32bit components of registers that can be   }
+      {           possible allocated to a regvar or using getregisterxxx (this }
+      {           excludes registers which can be only used for parameter      }
+      {           passing on ABI's that define this)                           }
+      { c_countusableregsxxx = amount of registers in the usableregsxxx set    }
+
+      maxintregs = 4;
+      intregs = [R_EAX..R_BL]-[R_ESI,R_SI];
+
+      maxfpuregs = 8;
+      fpuregs = [R_ST0..R_ST7];
+      usableregsfpu = [];
+      c_countusableregsfpu = 0;
+
+      mmregs = [R_MM0..R_MM7];
+      usableregsmm = [R_MM0..R_MM7];
+      c_countusableregsmm  = 8;
+
+{*****************************************************************************
+                            CPU Dependent Constants
+*****************************************************************************}
+
+    {$i cpubase.inc}
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    procedure convert_register_to_enum(var r:Tregister);
+    function cgsize2subreg(s:Tcgsize):Tsubregister;
+    function reg2opsize(r:tregister):topsize;
+    function is_calljmp(o:tasmop):boolean;
+    function flags_to_cond(const f: TResFlags) : TAsmCond;
+
+
+implementation
+
+    uses  verbose;
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    procedure convert_register_to_enum(var r:Tregister);
+
+    begin
+      if r.enum=R_INTREGISTER then
+        case r.number of
+          NR_NO:  r.enum:=R_NO;
+          NR_EAX: r.enum:=R_EAX;        NR_EBX: r.enum:=R_EBX;
+          NR_ECX: r.enum:=R_ECX;        NR_EDX: r.enum:=R_EDX;
+          NR_ESI: r.enum:=R_ESI;        NR_EDI: r.enum:=R_EDI;
+          NR_ESP: r.enum:=R_ESP;        NR_EBP: r.enum:=R_EBP;
+          NR_AX:  r.enum:=R_AX;         NR_BX:  r.enum:=R_BX;
+          NR_CX:  r.enum:=R_CX;         NR_DX:  r.enum:=R_DX;
+          NR_SI:  r.enum:=R_SI;         NR_DI:  r.enum:=R_DI;
+          NR_SP:  r.enum:=R_SP;         NR_BP:  r.enum:=R_BP;
+          NR_AL:  r.enum:=R_AL;         NR_BL:  r.enum:=R_BL;
+          NR_CL:  r.enum:=R_CL;         NR_DL:  r.enum:=R_DL;
+          NR_AH:  r.enum:=R_AH;         NR_BH:  r.enum:=R_BH;
+          NR_CH:  r.enum:=R_CH;         NR_DH:  r.enum:=R_DH;
+          NR_CS:  r.enum:=R_CS;         NR_DS:  r.enum:=R_DS;
+          NR_ES:  r.enum:=R_ES;         NR_FS:  r.enum:=R_FS;
+          NR_GS:  r.enum:=R_GS;         NR_SS:  r.enum:=R_SS;
+        else
+{          internalerror(200301082);}
+          r.enum:=R_TR3;
+        end;
+    end;
+
+    function cgsize2subreg(s:Tcgsize):Tsubregister;
+
+    begin
+      case s of
+        OS_8,OS_S8:
+          cgsize2subreg:=R_SUBL;
+        OS_16,OS_S16:
+          cgsize2subreg:=R_SUBW;
+        OS_32,OS_S32:
+          cgsize2subreg:=R_SUBD;
+        OS_64,OS_S64:
+          cgsize2subreg:=R_SUBQ;
+        else
+          internalerror(200301231);
+      end;
+    end;
+
+
+    function reg2opsize(r:Tregister):topsize;
+      const
+        subreg2opsize : array[0..4] of topsize = (S_B,S_B,S_W,S_L,S_D);
+
+{$ifdef x86_64}
+        enum2opsize:array[firstreg..lastreg] of topsize = (S_NO,
+          S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,
+          S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,
+          S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
+          S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
+          S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
+          S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
+          S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
+          S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
+          S_B,S_B,S_B,S_B,
+          S_W,S_W,S_W,S_W,S_W,S_W,
+          S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,
+          S_L,S_L,S_L,S_L,S_L,S_L,
+          S_L,S_L,S_L,S_L,
+          S_L,S_L,S_L,S_L,S_L,
+          S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
+          S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
+          S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D
+        );
+{$else x86_64}
+        enum2opsize : array[firstreg..lastreg] of topsize = (S_NO,
+          S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
+          S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
+          S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
+          S_W,S_W,S_W,S_W,S_W,S_W,
+          S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,
+          S_L,S_L,S_L,S_L,S_L,S_L,
+          S_L,S_L,S_L,S_L,
+          S_L,S_L,S_L,S_L,S_L,
+          S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
+          S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D
+        );
+{$endif x86_64}
+
+      begin
+        reg2opsize:=S_L;
+        if (r.enum=R_INTREGISTER) then
+         begin
+           if (r.number shr 8)=0 then
+            begin
+              case r.number of
+                NR_CS,NR_DS,NR_ES,
+                NR_SS,NR_FS,NR_GS :
+                  reg2opsize:=S_W;
+              end;
+            end
+           else
+            begin
+              if (r.number and $ff)>4 then
+                internalerror(200303181);
+              reg2opsize:=subreg2opsize[r.number and $ff];
+            end;
+         end
+        else
+         begin
+           reg2opsize:=enum2opsize[r.enum];
+         end;
+      end;
+
+{$ifdef unused}
+    function supreg_name(r:Tsuperregister):string;
+
+    var s:string[4];
+
+    const supreg_names:array[0..last_supreg] of string[4]=
+          ('INV',
+           'eax','ebx','ecx','edx','esi','edi','ebp','esp',
+           'r8' ,'r9', 'r10','r11','r12','r13','r14','r15');
+
+    begin
+      if r in [0..last_supreg] then
+        supreg_name:=supreg_names[r]
+      else
+        begin
+          str(r,s);
+          supreg_name:='reg'+s;
+        end;
+    end;
+{$endif unused}
+
+    function is_calljmp(o:tasmop):boolean;
+      begin
+        case o of
+          A_CALL,
+          A_JCXZ,
+          A_JECXZ,
+          A_JMP,
+          A_LOOP,
+          A_LOOPE,
+          A_LOOPNE,
+          A_LOOPNZ,
+          A_LOOPZ,
+          A_Jcc :
+            is_calljmp:=true;
+          else
+            is_calljmp:=false;
+        end;
+      end;
+
+
+    function flags_to_cond(const f: TResFlags) : TAsmCond;
+      const
+        flags_2_cond : array[TResFlags] of TAsmCond =
+          (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE);
+      begin
+        result := flags_2_cond[f];
+      end;
+
+
+end.
+{
+  $Log$
+  Revision 1.2  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.1  2003/04/25 11:12:09  florian
+    * merged i386/cpubase and x86_64/cpubase to x86/cpubase;
+      different stuff went to cpubase.inc
+
+  Revision 1.50  2003/04/25 08:25:26  daniel
+    * Ifdefs around a lot of calls to cleartempgen
+    * Fixed registers that are allocated but not freed in several nodes
+    * Tweak to register allocator to cause less spills
+    * 8-bit registers now interfere with esi,edi and ebp
+      Compiler can now compile rtl successfully when using new register
+      allocator
+
+  Revision 1.49  2003/04/22 23:50:23  peter
+    * firstpass uses expectloc
+    * checks if there are differences between the expectloc and
+      location.loc from secondpass in EXTDEBUG
+
+  Revision 1.48  2003/04/22 14:33:38  peter
+    * removed some notes/hints
+
+  Revision 1.47  2003/04/22 10:09:35  daniel
+    + Implemented the actual register allocator
+    + Scratch registers unavailable when new register allocator used
+    + maybe_save/maybe_restore unavailable when new register allocator used
+
+  Revision 1.46  2003/04/21 19:16:50  peter
+    * count address regs separate
+
+  Revision 1.45  2003/03/28 19:16:57  peter
+    * generic constructor working for i386
+    * remove fixed self register
+    * esi added as address register for i386
+
+  Revision 1.44  2003/03/18 18:15:53  peter
+    * changed reg2opsize to function
+
+  Revision 1.43  2003/03/08 08:59:07  daniel
+    + $define newra will enable new register allocator
+    + getregisterint will return imaginary registers with $newra
+    + -sr switch added, will skip register allocation so you can see
+      the direct output of the code generator before register allocation
+
+  Revision 1.42  2003/02/19 22:00:15  daniel
+    * Code generator converted to new register notation
+    - Horribily outdated todo.txt removed
+
+  Revision 1.41  2003/02/02 19:25:54  carl
+    * Several bugfixes for m68k target (register alloc., opcode emission)
+    + VIS target
+    + Generic add more complete (still not verified)
+
+  Revision 1.40  2003/01/13 18:37:44  daniel
+    * Work on register conversion
+
+  Revision 1.39  2003/01/09 20:41:00  daniel
+    * Converted some code in cgx86.pas to new register numbering
+
+  Revision 1.38  2003/01/09 15:49:56  daniel
+    * Added register conversion
+
+  Revision 1.37  2003/01/08 22:32:36  daniel
+    * Added register convesrion procedure
+
+  Revision 1.36  2003/01/08 18:43:57  daniel
+   * Tregister changed into a record
+
+  Revision 1.35  2003/01/05 13:36:53  florian
+    * x86-64 compiles
+    + very basic support for float128 type (x86-64 only)
+
+  Revision 1.34  2002/11/17 18:26:16  mazen
+  * fixed a compilation bug accmulator-->accumulator, in definition of return_result_reg
+
+  Revision 1.33  2002/11/17 17:49:08  mazen
+  + return_result_reg and function_result_reg are now used, in all plateforms, to pass functions result between called function and its caller. See the explanation of each one
+
+  Revision 1.32  2002/10/05 12:43:29  carl
+    * fixes for Delphi 6 compilation
+     (warning : Some features do not work under Delphi)
+
+  Revision 1.31  2002/08/14 18:41:48  jonas
+    - remove valuelow/valuehigh fields from tlocation, because they depend
+      on the endianess of the host operating system -> difficult to get
+      right. Use lo/hi(location.valueqword) instead (remember to use
+      valueqword and not value!!)
+
+  Revision 1.30  2002/08/13 21:40:58  florian
+    * more fixes for ppc calling conventions
+
+  Revision 1.29  2002/08/12 15:08:41  carl
+    + stab register indexes for powerpc (moved from gdb to cpubase)
+    + tprocessor enumeration moved to cpuinfo
+    + linker in target_info is now a class
+    * many many updates for m68k (will soon start to compile)
+    - removed some ifdef or correct them for correct cpu
+
+  Revision 1.28  2002/08/06 20:55:23  florian
+    * first part of ppc calling conventions fix
+
+  Revision 1.27  2002/07/25 18:01:29  carl
+    + FPURESULTREG -> FPU_RESULT_REG
+
+  Revision 1.26  2002/07/07 09:52:33  florian
+    * powerpc target fixed, very simple units can be compiled
+    * some basic stuff for better callparanode handling, far from being finished
+
+  Revision 1.25  2002/07/01 18:46:30  peter
+    * internal linker
+    * reorganized aasm layer
+
+  Revision 1.24  2002/07/01 16:23:55  peter
+    * cg64 patch
+    * basics for currency
+    * asnode updates for class and interface (not finished)
+
+  Revision 1.23  2002/05/18 13:34:22  peter
+    * readded missing revisions
+
+  Revision 1.22  2002/05/16 19:46:50  carl
+  + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
+  + try to fix temp allocation (still in ifdef)
+  + generic constructor calls
+  + start of tassembler / tmodulebase class cleanup
+
+  Revision 1.19  2002/05/12 16:53:16  peter
+    * moved entry and exitcode to ncgutil and cgobj
+    * foreach gets extra argument for passing local data to the
+      iterator function
+    * -CR checks also class typecasts at runtime by changing them
+      into as
+    * fixed compiler to cycle with the -CR option
+    * fixed stabs with elf writer, finally the global variables can
+      be watched
+    * removed a lot of routines from cga unit and replaced them by
+      calls to cgobj
+    * u32bit-s32bit updates for and,or,xor nodes. When one element is
+      u32bit then the other is typecasted also to u32bit without giving
+      a rangecheck warning/error.
+    * fixed pascal calling method with reversing also the high tree in
+      the parast, detected by tcalcst3 test
+
+  Revision 1.18  2002/04/21 15:31:40  carl
+  - removed some other stuff to their units
+
+  Revision 1.17  2002/04/20 21:37:07  carl
+  + generic FPC_CHECKPOINTER
+  + first parameter offset in stack now portable
+  * rename some constants
+  + move some cpu stuff to other units
+  - remove unused constents
+  * fix stacksize for some targets
+  * fix generic size problems which depend now on EXTEND_SIZE constant
+  * removing frame pointer in routines is only available for : i386,m68k and vis targets
+
+  Revision 1.16  2002/04/15 19:53:54  peter
+    * fixed conflicts between the last 2 commits
+
+  Revision 1.15  2002/04/15 19:44:20  peter
+    * fixed stackcheck that would be called recursively when a stack
+      error was found
+    * generic changeregsize(reg,size) for i386 register resizing
+    * removed some more routines from cga unit
+    * fixed returnvalue handling
+    * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
+
+  Revision 1.14  2002/04/15 19:12:09  carl
+  + target_info.size_of_pointer -> pointer_size
+  + some cleanup of unused types/variables
+  * move several constants from cpubase to their specific units
+    (where they are used)
+  + att_Reg2str -> gas_reg2str
+  + int_reg2str -> std_reg2str
+
+  Revision 1.13  2002/04/14 16:59:41  carl
+  + att_reg2str -> gas_reg2str
+
+  Revision 1.12  2002/04/02 17:11:34  peter
+    * tlocation,treference update
+    * LOC_CONSTANT added for better constant handling
+    * secondadd splitted in multiple routines
+    * location_force_reg added for loading a location to a register
+      of a specified size
+    * secondassignment parses now first the right and then the left node
+      (this is compatible with Kylix). This saves a lot of push/pop especially
+      with string operations
+    * adapted some routines to use the new cg methods
+
+  Revision 1.11  2002/03/31 20:26:37  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.10  2002/03/04 19:10:12  peter
+    * removed compiler warnings
+
+}

+ 187 - 0
compiler/x86_64/cpubase.inc

@@ -0,0 +1,187 @@
+{
+    $Id$
+    Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
+
+    Contains the basic declarations for the x86-64 architecture
+
+    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 include file contains the basic declarations for the x86-64 architecture.
+}
+
+{*****************************************************************************
+                                Operand Sizes
+*****************************************************************************}
+
+type
+  topsize = (S_NO,
+    S_B,S_W,S_L,S_BW,S_BL,S_WL,S_BQ,S_WQ,S_LQ,
+    S_IS,S_IL,S_IQ,
+    S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX,
+    S_NEAR,S_FAR,S_SHORT
+  );
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+const
+  { Standard opcode string table (for each tasmop enumeration). The
+    opcode strings should conform to the names as defined by the
+    processor manufacturer.
+  }
+  std_op2str:op2strtable={$i x86_64in.inc}
+
+  { Standard register table (for each tregister enumeration). The
+    register strings should conform to the the names as defined
+    by the processor manufacturer
+  }
+  std_reg2str : reg2strtable = ('',
+    'rax','rcx','rdx','rbx','rsp','rbp','rsi','rdi',
+    'r8','r9','r10','r11','r12','r13','r14','r15','rip',
+    'eax','ecx','edx','ebx','esp','ebp','esi','edi',
+    'r8d','r9d','r10d','r11d','r12d','r13d','r14d','r15d',
+    'ax','cx','dx','bx','sp','bp','si','di',
+    'r8w','r9w','r10w','r11w','r12w','r13w','r14w','r15w',
+    'al','cl','dl','bl','spl','bpl','sil','dil',
+    'r8b','r9b','r10b','r11b','r12b','r13b','r14b','r15b',
+    'ah','ch','bh','dh',
+    'cs','ds','es','ss','fs','gs',
+    'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)',
+    'dr0','dr1','dr2','dr3','dr6','dr7',
+    'cr0','cr2','cr3','cr4',
+    'tr3','tr4','tr5','tr6','tr7',
+    'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
+    'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7',
+    'xmm8','xmm9','xmm10','xmm11','xmm12','xmm13','xmm14','xmm15');
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      firstsaveintreg = R_EAX;
+      lastsaveintreg  = R_R15;
+      firstsavefpureg = R_NO;
+      lastsavefpureg  = R_NO;
+      firstsavemmreg  = R_XMM0;
+      lastsavemmreg   = R_XMM15;
+
+      general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
+      general_superregisters = [RS_RAX,RS_RBX,RS_RCX,RS_RDX];
+
+{$ifdef newra}
+      usableregsint = [first_imreg..last_imreg];
+{$else}
+      usableregsint = [RS_RAX,RS_RBX,RS_RCX,RS_RDX];
+{$endif}
+      c_countusableregsint = 4;
+
+      maxaddrregs = 1;
+      addrregs    = [R_ESI];
+      usableregsaddr = [RS_RSI];
+      c_countusableregsaddr = 1;
+
+      maxvarregs = 4;
+      varregs : array[1..maxvarregs] of Toldregister =
+         (R_EBX,R_EDX,R_ECX,R_EAX);
+
+      maxfpuvarregs = 8;
+
+      {# Registers which are defined as scratch and no need to save across
+         routine calls or in assembler blocks.
+      }
+{$ifndef newra}
+      max_scratch_regs = 1;
+      scratch_regs : array[1..max_scratch_regs] of Tsuperregister = (RS_RDI);
+{$endif}
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+      { Defines the default address size for a processor, }
+      OS_ADDR = OS_64;
+      { the natural int size for a processor,             }
+      OS_INT = OS_64;
+      { the maximum float size for a processor,           }
+      OS_FLOAT = OS_F80;
+      { the size of a vector register for a processor     }
+      OS_VECTOR = OS_M64;
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      {# Stack pointer register }
+      stack_pointer_reg = R_RSP;
+      NR_STACK_POINTER_REG = NR_RSP;
+      {# Frame pointer register }
+      frame_pointer_reg = R_RBP;
+      NR_FRAME_POINTER_REG = NR_RBP;
+      { Register for addressing absolute data in a position independant way,
+        such as in PIC code. The exact meaning is ABI specific. For
+        further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
+      }
+      pic_offset_reg = R_EBX;
+      accumulator = R_RAX;
+      RS_ACCUMULATOR = RS_RAX;
+      NR_ACCUMULATOR = NR_RAX;
+      { the return_result_reg, is used inside the called function to store its return
+        value when that is a scalar value otherwise a pointer to the address of the
+        result is placed inside it }
+      return_result_reg   = accumulator;
+      RS_RETURN_RESULT_REG = RS_ACCUMULATOR;
+      NR_RETURN_RESULT_REG = NR_ACCUMULATOR;
+
+      { the function_result_reg contains the function result after a call to a scalar
+        function othewise it contains a pointer to the returned result}
+      function_result_reg = accumulator;
+
+      fpu_result_reg = R_ST;
+      mmresultreg = R_MM0;
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+    const
+      { Registers which must be saved when calling a routine declared as
+        cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+        saved should be the ones as defined in the target ABI and / or GCC.
+
+        This value can be deduced from the CALLED_USED_REGISTERS array in the
+        GCC source.
+      }
+      std_saved_registers = [R_ESI,R_EDI,R_EBX];
+      { Required parameter alignment when calling a routine declared as
+        stdcall and cdecl. The alignment value should be the one defined
+        by GCC or the target ABI.
+
+         The value of this constant is equal to the constant
+         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+      }
+      std_param_align = 8;
+
+{
+  $Log$
+  Revision 1.2  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.1  2003/04/25 11:12:09  florian
+    * merged i386/cpubase and x86_64/cpubase to x86/cpubase;
+      different stuff went to cpubase.inc
+}

+ 147 - 0
compiler/x86_64/cpupara.pas

@@ -0,0 +1,147 @@
+{
+    $Id$
+    Copyright (c) 2002 by Florian Klaempfl
+
+    Generates the argument location information for x86-64 target
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published bymethodpointer
+    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.
+
+ ****************************************************************************
+}
+{ Generates the argument location information for x86-64 target.
+}
+unit cpupara;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       cpubase,
+       symconst,symbase,symtype,symdef,paramgr;
+
+    type
+       { Returns the location for the nr-st 32 Bit int parameter
+         if every parameter before is an 32 Bit int parameter as well
+         and if the calling conventions for the helper routines of the
+         rtl are used.
+       }
+       tx86_64paramanager = class(tparamanager)
+          function getintparaloc(nr : longint) : tparalocation;override;
+          procedure create_param_loc_info(p : tabstractprocdef);override;
+       end;
+
+  implementation
+
+    uses
+       verbose,
+       globtype,
+       cpuinfo,cginfo,cgbase,
+       defutil;
+
+    function getparaloc(p : tdef) : tcgloc;
+
+      begin
+         { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
+           if push_addr_param for the def is true
+         }
+         // !!!!! Fix aggregate types
+         case p.deftype of
+            orddef:
+              getparaloc:=LOC_REGISTER;
+            floatdef:
+              case tfloatdef(p).typ of
+                 s80real:
+                   getparaloc:=LOC_REFERENCE;
+                 s32real,
+                 s64real,
+                 s64comp,
+                 s64currency,
+                 s128real:
+                   getparaloc:=LOC_MMREGISTER;
+              end;
+            enumdef:
+              getparaloc:=LOC_REGISTER;
+            pointerdef:
+              getparaloc:=LOC_REGISTER;
+            formaldef:
+              getparaloc:=LOC_REGISTER;
+            classrefdef:
+              getparaloc:=LOC_REGISTER;
+            recorddef:
+              getparaloc:=LOC_REFERENCE;
+            objectdef:
+              if is_object(p) then
+                getparaloc:=LOC_REFERENCE
+              else
+                getparaloc:=LOC_REGISTER;
+            stringdef:
+              if is_shortstring(p) or is_longstring(p) then
+                getparaloc:=LOC_REFERENCE
+              else
+                getparaloc:=LOC_REGISTER;
+            procvardef:
+              if (po_methodpointer in tprocvardef(p).procoptions) then
+                getparaloc:=LOC_REFERENCE
+              else
+                getparaloc:=LOC_REGISTER;
+            filedef:
+              getparaloc:=LOC_REGISTER;
+            arraydef:
+              getparaloc:=LOC_REFERENCE;
+            setdef:
+              if is_smallset(p) then
+                getparaloc:=LOC_REGISTER
+              else
+                getparaloc:=LOC_REFERENCE;
+            variantdef:
+              getparaloc:=LOC_REFERENCE;
+            { avoid problems with errornous definitions }
+            errordef:
+              getparaloc:=LOC_REGISTER;
+            else
+              internalerror(2002071001);
+         end;
+      end;
+
+    function tx86_64paramanager.getintparaloc(nr : longint) : tparalocation;
+      begin
+      end;
+
+    procedure tx86_64paramanager.create_param_loc_info(p : tabstractprocdef);
+      begin
+         { set default para_alignment to target_info.stackalignment }
+         { if para_alignment=0 then
+           para_alignment:=aktalignment.paraalign;
+         }
+      end;
+
+
+begin
+   paramanager:=tx86_64paramanager.create;
+end.
+{
+  $Log$
+  Revision 1.3  2002-04-25 16:12:09  florian
+    * fixed more problems with cpubase and x86-64
+
+  Revision 1.2  2003/01/05 13:36:54  florian
+    * x86-64 compiles
+    + very basic support for float128 type (x86-64 only)
+
+  Revision 1.1  2002/07/24 22:38:15  florian
+    + initial release of x86-64 target code
+
+}