Просмотр исходного кода

all the extra i8086 units added

git-svn-id: branches/i8086@23718 -
nickysn 12 лет назад
Родитель
Сommit
eff0894a66

+ 9 - 0
.gitattributes

@@ -237,8 +237,14 @@ compiler/i386/ra386att.pas svneol=native#text/plain
 compiler/i386/ra386int.pas svneol=native#text/plain
 compiler/i386/rgcpu.pas svneol=native#text/plain
 compiler/i386/rropt386.pas svneol=native#text/plain
+compiler/i8086/cgcpu.pas svneol=native#text/plain
 compiler/i8086/cpubase.inc svneol=native#text/plain
 compiler/i8086/cpuinfo.pas svneol=native#text/plain
+compiler/i8086/cpunode.pas svneol=native#text/plain
+compiler/i8086/cpupara.pas svneol=native#text/plain
+compiler/i8086/cpupi.pas svneol=native#text/plain
+compiler/i8086/cputarg.pas svneol=native#text/plain
+compiler/i8086/hlcgcpu.pas svneol=native#text/plain
 compiler/i8086/i386att.inc svneol=native#text/plain
 compiler/i8086/i386atts.inc svneol=native#text/plain
 compiler/i8086/i386int.inc svneol=native#text/plain
@@ -262,6 +268,9 @@ compiler/i8086/r386rni.inc svneol=native#text/plain
 compiler/i8086/r386sri.inc svneol=native#text/plain
 compiler/i8086/r386stab.inc svneol=native#text/plain
 compiler/i8086/r386std.inc svneol=native#text/plain
+compiler/i8086/ra8086att.pas svneol=native#text/plain
+compiler/i8086/ra8086int.pas svneol=native#text/plain
+compiler/i8086/rgcpu.pas svneol=native#text/plain
 compiler/ia64/aasmcpu.pas svneol=native#text/plain
 compiler/ia64/cpubase.pas svneol=native#text/plain
 compiler/ia64/cpuinfo.pas svneol=native#text/plain

+ 2 - 2
compiler/compiler.pas

@@ -35,7 +35,7 @@ uses
 {$endif WATCOM}
 {$ifdef unix}
   { system code page stuff for unix }
-  unixcp,
+//  unixcp,
 {$endif}
 {$IFNDEF USE_FAKE_SYSUTILS}
   sysutils,math,
@@ -179,7 +179,7 @@ begin
    DoneCompiler;
 {$ifdef unix}
   { Set default code page for ansistrings on unix-like systems }
-  DefaultSystemCodePage:=GetSystemCodePage;
+//  DefaultSystemCodePage:=GetSystemCodePage;
 {$endif}
 { inits which need to be done before the arguments are parsed }
   InitSystems;

+ 1179 - 0
compiler/i8086/cgcpu.pas

@@ -0,0 +1,1179 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the code generator for the i386
+
+    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 cgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,
+       cgbase,cgobj,cg64f32,cgx86,
+       aasmbase,aasmtai,aasmdata,aasmcpu,
+       cpubase,parabase,cgutils,
+       symconst,symdef
+       ;
+
+    type
+      tcg8086 = class(tcgx86)
+        procedure init_register_allocators;override;
+        procedure do_register_allocation(list:TAsmList;headertai:tai);override;
+
+        function getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
+
+        { passing parameter using push instead of mov }
+        procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
+        procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
+        procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
+        procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
+
+        { move instructions }
+        procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
+        procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
+        procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
+        procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
+        procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
+
+        procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
+        procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
+        procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
+
+        procedure g_exception_reason_save(list : TAsmList; const href : treference);override;
+        procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: tcgint);override;
+        procedure g_exception_reason_load(list : TAsmList; const href : treference);override;
+        procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+        procedure g_maybe_got_init(list: TAsmList); override;
+     end;
+
+      tcg64f386 = class(tcg64f32)
+        procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
+        procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
+        procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
+        procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
+      private
+        procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
+      end;
+
+    procedure create_codegen;
+
+  implementation
+
+    uses
+       globals,verbose,systems,cutils,
+       paramgr,procinfo,fmodule,
+       rgcpu,rgx86,cpuinfo;
+
+    function use_push(const cgpara:tcgpara):boolean;
+      begin
+        result:=(not paramanager.use_fixed_stack) and
+                assigned(cgpara.location) and
+                (cgpara.location^.loc=LOC_REFERENCE) and
+                (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
+      end;
+
+
+    procedure tcg8086.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        if not(target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+           (cs_create_pic in current_settings.moduleswitches) then
+          rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI],first_int_imreg,[RS_BP])
+        else
+          if (cs_useebp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer<>NR_BP) then
+            rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI,RS_BP],first_int_imreg,[])
+          else
+            rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI],first_int_imreg,[RS_BP]);
+        rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
+        rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBWHOLE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
+        rgfpu:=Trgx86fpu.create;
+      end;
+
+    procedure tcg8086.do_register_allocation(list:TAsmList;headertai:tai);
+      begin
+        if (pi_needs_got in current_procinfo.flags) then
+          begin
+            if getsupreg(current_procinfo.got) < first_int_imreg then
+              include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
+          end;
+        inherited do_register_allocation(list,headertai);
+      end;
+
+
+    function tcg8086.getintregister(list: TAsmList; size: Tcgsize): Tregister;
+      begin
+        case size of
+          OS_8, OS_S8,
+          OS_16, OS_S16:
+            Result := inherited getintregister(list, size);
+          OS_32, OS_S32:
+            begin
+              Result:=inherited getintregister(list, OS_16);
+              { ensure that the high register can be retrieved by
+                GetNextReg
+              }
+              if inherited getintregister(list, OS_16)<>GetNextReg(Result) then
+                internalerror(2013030202);
+            end;
+          else
+            internalerror(2013030201);
+        end;
+      end;
+
+
+    procedure tcg8086.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
+      var
+        pushsize : tcgsize;
+      begin
+        check_register_size(size,r);
+        if use_push(cgpara) then
+          begin
+            cgpara.check_simple_location;
+            if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
+              pushsize:=cgpara.location^.size
+            else
+              pushsize:=int_cgsize(cgpara.alignment);
+            list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
+          end
+        else
+          inherited a_load_reg_cgpara(list,size,r,cgpara);
+      end;
+
+
+    procedure tcg8086.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
+      var
+        pushsize : tcgsize;
+      begin
+        if use_push(cgpara) then
+          begin
+            cgpara.check_simple_location;
+            if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
+              pushsize:=cgpara.location^.size
+            else
+              pushsize:=int_cgsize(cgpara.alignment);
+            list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
+          end
+        else
+          inherited a_load_const_cgpara(list,size,a,cgpara);
+      end;
+
+
+    procedure tcg8086.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
+
+        procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
+        var
+          pushsize : tcgsize;
+          opsize : topsize;
+          tmpreg   : tregister;
+          href     : treference;
+        begin
+          if not assigned(paraloc) then
+            exit;
+          if (paraloc^.loc<>LOC_REFERENCE) or
+             (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
+             (tcgsize2size[paraloc^.size]>sizeof(aint)) then
+            internalerror(200501162);
+          { Pushes are needed in reverse order, add the size of the
+            current location to the offset where to load from. This
+            prevents wrong calculations for the last location when
+            the size is not a power of 2 }
+          if assigned(paraloc^.next) then
+            pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
+          { Push the data starting at ofs }
+          href:=r;
+          inc(href.offset,ofs);
+          if tcgsize2size[paraloc^.size]>cgpara.alignment then
+            pushsize:=paraloc^.size
+          else
+            pushsize:=int_cgsize(cgpara.alignment);
+          opsize:=TCgsize2opsize[pushsize];
+          { for go32v2 we obtain OS_F32,
+            but pushs is not valid, we need pushl }
+          if opsize=S_FS then
+            opsize:=S_L;
+          if tcgsize2size[paraloc^.size]<cgpara.alignment then
+            begin
+              tmpreg:=getintregister(list,pushsize);
+              a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
+              list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+            end
+          else
+            begin
+              make_simple_ref(list,href);
+              list.concat(taicpu.op_ref(A_PUSH,opsize,href));
+            end;
+        end;
+
+      var
+        len : tcgint;
+        href : treference;
+      begin
+        { cgpara.size=OS_NO requires a copy on the stack }
+        if use_push(cgpara) then
+          begin
+            { Record copy? }
+            if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
+              begin
+                cgpara.check_simple_location;
+                len:=align(cgpara.intsize,cgpara.alignment);
+                g_stackpointer_alloc(list,len);
+                reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
+                g_concatcopy(list,r,href,len);
+              end
+            else
+              begin
+                if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
+                  internalerror(200501161);
+                { We need to push the data in reverse order,
+                  therefor we use a recursive algorithm }
+                pushdata(cgpara.location,0);
+              end
+          end
+        else
+          inherited a_load_ref_cgpara(list,size,r,cgpara);
+      end;
+
+
+    procedure tcg8086.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
+      var
+        tmpreg : tregister;
+        opsize : topsize;
+        tmpref : treference;
+      begin
+        with r do
+          begin
+            if use_push(cgpara) then
+              begin
+                cgpara.check_simple_location;
+                opsize:=tcgsize2opsize[OS_ADDR];
+                if (segment=NR_NO) and (base=NR_NO) and (index=NR_NO) then
+                  begin
+                    if assigned(symbol) then
+                      begin
+                        if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+                           ((r.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL]) or
+                            (cs_create_pic in current_settings.moduleswitches)) then
+                          begin
+                            tmpreg:=getaddressregister(list);
+                            a_loadaddr_ref_reg(list,r,tmpreg);
+                            list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+                          end
+                        else if cs_create_pic in current_settings.moduleswitches then
+                          begin
+                            if offset<>0 then
+                              begin
+                                tmpreg:=getaddressregister(list);
+                                a_loadaddr_ref_reg(list,r,tmpreg);
+                                list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+                              end
+                            else
+                              begin
+                                reference_reset_symbol(tmpref,r.symbol,0,r.alignment);
+                                tmpref.refaddr:=addr_pic;
+                                tmpref.base:=current_procinfo.got;
+{$ifdef EXTDEBUG}
+				if not (pi_needs_got in current_procinfo.flags) then
+				  Comment(V_warning,'pi_needs_got not included');
+{$endif EXTDEBUG}
+                                include(current_procinfo.flags,pi_needs_got);
+                                list.concat(taicpu.op_ref(A_PUSH,S_L,tmpref));
+                              end
+                          end
+                        else
+                          list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset));
+                      end
+                    else
+                      list.concat(Taicpu.Op_const(A_PUSH,opsize,offset));
+                  end
+                else if (segment=NR_NO) and (base=NR_NO) and (index<>NR_NO) and
+                        (offset=0) and (scalefactor=0) and (symbol=nil) then
+                  list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
+                else if (segment=NR_NO) and (base<>NR_NO) and (index=NR_NO) and
+                        (offset=0) and (symbol=nil) then
+                  list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
+                else
+                  begin
+                    tmpreg:=getaddressregister(list);
+                    a_loadaddr_ref_reg(list,r,tmpreg);
+                    list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
+                  end;
+              end
+            else
+              inherited a_loadaddr_ref_cgpara(list,r,cgpara);
+          end;
+      end;
+
+
+    procedure tcg8086.a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);
+    begin
+      check_register_size(tosize,reg);
+      if tosize in [OS_S32,OS_32] then
+        begin
+          list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a and $ffff),reg));
+          list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a shr 16),GetNextReg(reg)));
+        end
+      else
+        list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg));
+    end;
+
+
+    procedure tcg8086.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
+      var
+        tmpref : treference;
+      begin
+        tmpref:=ref;
+        make_simple_ref(list,tmpref);
+
+        if tosize in [OS_S32,OS_32] then
+          begin
+            a_load_const_ref(list,OS_16,longint(a and $ffff),tmpref);
+            inc(tmpref.offset,2);
+            a_load_const_ref(list,OS_16,longint(a shr 16),tmpref);
+          end
+        else
+          list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
+      end;
+
+
+
+    procedure tcg8086.a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);
+      var
+        tmpsize : tcgsize;
+        tmpreg  : tregister;
+        tmpref  : treference;
+      begin
+        tmpref:=ref;
+        make_simple_ref(list,tmpref);
+        check_register_size(fromsize,reg);
+
+        case tosize of
+          OS_8,OS_S8:
+            if fromsize in [OS_8,OS_S8] then
+              list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
+            else
+              internalerror(2013030310);
+          OS_16,OS_S16:
+            if fromsize in [OS_16,OS_S16] then
+              list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref))
+            else
+              internalerror(2013030312);
+          OS_32,OS_S32:
+            if fromsize in [OS_32,OS_S32] then
+              begin
+                list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
+                inc(tmpref.offset, 2);
+                list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
+              end
+            else
+              internalerror(2013030313);
+          else
+            internalerror(2013030311);
+        end;
+      end;
+
+
+    procedure tcg8086.a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);
+
+        procedure add_mov(instr: Taicpu);
+          begin
+            { Notify the register allocator that we have written a move instruction so
+              it can try to eliminate it. }
+            if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
+              add_move_instruction(instr);
+            list.concat(instr);
+          end;
+
+      var
+        tmpref  : treference;
+      begin
+        tmpref:=ref;
+        make_simple_ref(list,tmpref);
+        check_register_size(tosize,reg);
+
+        if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+          internalerror(2011021307);
+{        if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
+          fromsize:=tosize;}
+
+        case tosize of
+          OS_8,OS_S8:
+            if fromsize in [OS_8,OS_S8] then
+              list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
+            else
+              internalerror(2013030210);
+          OS_16,OS_S16:
+            case fromsize of
+              OS_8:
+                begin
+                  list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
+                  reg := makeregsize(list, reg, OS_8);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
+                end;
+              OS_S8:
+                begin
+                  getcpuregister(list, NR_AX);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
+                  list.concat(taicpu.op_none(A_CBW));
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
+                  ungetcpuregister(list, NR_AX);
+                end;
+              OS_16,OS_S16:
+                list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
+              else
+                internalerror(2013030212);
+            end;
+          OS_32,OS_S32:
+            case fromsize of
+              OS_8:
+                begin
+                  list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
+                  list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
+                  reg := makeregsize(list, reg, OS_8);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
+                end;
+              OS_S8:
+                begin
+                  getcpuregister(list, NR_AX);
+                  getcpuregister(list, NR_DX);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
+                  list.concat(taicpu.op_none(A_CBW));
+                  list.concat(taicpu.op_none(A_CWD));
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
+                  ungetcpuregister(list, NR_AX);
+                  ungetcpuregister(list, NR_DX);
+                end;
+              OS_16:
+                begin
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
+                  list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
+                end;
+              OS_S16:
+                begin
+                  getcpuregister(list, NR_AX);
+                  getcpuregister(list, NR_DX);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
+                  list.concat(taicpu.op_none(A_CWD));
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
+                  ungetcpuregister(list, NR_AX);
+                  ungetcpuregister(list, NR_DX);
+                end;
+              OS_32,OS_S32:
+                begin
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
+                  inc(tmpref.offset, 2);
+                  list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
+                end;
+              else
+                internalerror(2013030213);
+            end;
+          else
+            internalerror(2013030211);
+        end;
+      end;
+
+
+    procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
+
+        procedure add_mov(instr: Taicpu);
+          begin
+            { Notify the register allocator that we have written a move instruction so
+              it can try to eliminate it. }
+            if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
+              add_move_instruction(instr);
+            list.concat(instr);
+          end;
+
+//      var
+//        op: tasmop;
+//        s: topsize;
+//        instr:Taicpu;
+      begin
+        check_register_size(fromsize,reg1);
+        check_register_size(tosize,reg2);
+
+        if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
+          fromsize:=tosize;
+
+{        if tcgsize2size[fromsize]>tcgsize2size[tosize] then
+          begin
+            reg1:=makeregsize(list,reg1,tosize);
+            s:=tcgsize2opsize[tosize];
+            op:=A_MOV;
+          end
+        else
+          sizes2load(fromsize,tosize,op,s);}
+
+        if (reg1<>reg2) then
+          begin
+            case tosize of
+              OS_8,OS_S8:
+                if fromsize in [OS_8,OS_S8] then
+                  add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2))
+                else
+                  internalerror(2013030210);
+              OS_16,OS_S16:
+                case fromsize of
+                  OS_8:
+                    begin
+                      list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg2));
+                      reg2 := makeregsize(list, reg2, OS_8);
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
+                    end;
+                  OS_S8:
+                    begin
+                      getcpuregister(list, NR_AX);
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
+                      list.concat(taicpu.op_none(A_CBW));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
+                      ungetcpuregister(list, NR_AX);
+                    end;
+                  OS_16,OS_S16:
+                    add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
+                  else
+                    internalerror(2013030212);
+                end;
+              OS_32,OS_S32:
+                case fromsize of
+                  OS_8:
+                    begin
+                      list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
+                      list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg2));
+                      reg2 := makeregsize(list, reg2, OS_8);
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
+                    end;
+                  OS_S8:
+                    begin
+                      getcpuregister(list, NR_AX);
+                      getcpuregister(list, NR_DX);
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
+                      list.concat(taicpu.op_none(A_CBW));
+                      list.concat(taicpu.op_none(A_CWD));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
+                      ungetcpuregister(list, NR_AX);
+                      ungetcpuregister(list, NR_DX);
+                    end;
+                  OS_16:
+                    begin
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
+                      list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
+                    end;
+                  OS_S16:
+                    begin
+                      getcpuregister(list, NR_AX);
+                      getcpuregister(list, NR_DX);
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
+                      list.concat(taicpu.op_none(A_CWD));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
+                      ungetcpuregister(list, NR_AX);
+                      ungetcpuregister(list, NR_DX);
+                    end;
+                  OS_32,OS_S32:
+                    begin
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
+                      add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
+                    end;
+                  else
+                    internalerror(2013030213);
+                end;
+              else
+                internalerror(2013030211);
+            end;
+          end;
+      end;
+
+
+    procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
+      var
+        stacksize : longint;
+      begin
+        { MMX needs to call EMMS }
+        if assigned(rg[R_MMXREGISTER]) and
+           (rg[R_MMXREGISTER].uses_registers) then
+          list.concat(Taicpu.op_none(A_EMMS,S_NO));
+
+        { remove stackframe }
+        if not nostackframe then
+          begin
+            if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
+              begin
+                stacksize:=current_procinfo.calc_stackframe_size;
+                if (target_info.stackalign>4) and
+                   ((stacksize <> 0) or
+                    (pi_do_call in current_procinfo.flags) or
+                    { can't detect if a call in this case -> use nostackframe }
+                    { if you (think you) know what you are doing              }
+                    (po_assembler in current_procinfo.procdef.procoptions)) then
+                  stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
+                if (stacksize<>0) then
+                  cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
+              end
+            else
+              begin
+                list.concat(Taicpu.op_reg_reg(A_MOV, S_W, NR_BP, NR_SP));
+                list.concat(Taicpu.op_reg(A_POP, S_W, NR_BP));
+                {todo: use LEAVE for 286+}
+                {list.concat(Taicpu.op_none(A_LEAVE,S_NO));}
+              end;
+            list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
+          end;
+
+        { return from proc }
+        if (po_interrupt in current_procinfo.procdef.procoptions) and
+           { this messes up stack alignment }
+           (target_info.stackalign=4) then
+          begin
+            if assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
+               (current_procinfo.procdef.funcretloc[calleeside].location^.loc=LOC_REGISTER) then
+              begin
+                if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.register)=RS_EAX) then
+                  list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
+                else
+                  internalerror(2010053001);
+              end
+            else
+              list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
+            list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
+            list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
+
+            if (current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64]) and
+               assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
+               assigned(current_procinfo.procdef.funcretloc[calleeside].location^.next) and
+               (current_procinfo.procdef.funcretloc[calleeside].location^.next^.loc=LOC_REGISTER) then
+              begin
+                if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.next^.register)=RS_EDX) then
+                  list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
+                else
+                  internalerror(2010053002);
+              end
+            else
+              list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
+
+            list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
+            list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
+            { .... also the segment registers }
+            list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
+            list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
+            list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
+            list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
+            { this restores the flags }
+            list.concat(Taicpu.Op_none(A_IRET,S_NO));
+          end
+        { Routines with the poclearstack flag set use only a ret }
+        else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
+                (not paramanager.use_fixed_stack)  then
+         begin
+           { complex return values are removed from stack in C code PM }
+           { but not on win32 }
+           { and not for safecall with hidden exceptions, because the result }
+           { wich contains the exception is passed in EAX }
+           if (target_info.system <> system_i386_win32) and
+              not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
+               (tf_safecall_exceptions in target_info.flags)) and
+              paramanager.ret_in_param(current_procinfo.procdef.returndef,
+                                       current_procinfo.procdef) then
+             list.concat(Taicpu.Op_const(A_RET,S_W,sizeof(aint)))
+           else
+             list.concat(Taicpu.Op_none(A_RET,S_NO));
+         end
+        { ... also routines with parasize=0 }
+        else if (parasize=0) then
+         list.concat(Taicpu.Op_none(A_RET,S_NO))
+        else
+         begin
+           { parameters are limited to 65535 bytes because ret allows only imm16 }
+           if (parasize>65535) then
+             CGMessage(cg_e_parasize_too_big);
+           list.concat(Taicpu.Op_const(A_RET,S_W,parasize));
+         end;
+      end;
+
+
+    procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
+      var
+        power,len  : longint;
+        opsize : topsize;
+{$ifndef __NOWINPECOFF__}
+        again,ok : tasmlabel;
+{$endif}
+      begin
+        { get stack space }
+        getcpuregister(list,NR_EDI);
+        a_load_loc_reg(list,OS_INT,lenloc,NR_EDI);
+        list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
+        { Now EDI contains (high+1). Copy it to ECX for later use. }
+        getcpuregister(list,NR_ECX);
+        list.concat(Taicpu.op_reg_reg(A_MOV,S_L,NR_EDI,NR_ECX));
+        if (elesize<>1) then
+         begin
+           if ispowerof2(elesize, power) then
+             list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
+           else
+             list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
+         end;
+{$ifndef __NOWINPECOFF__}
+        { windows guards only a few pages for stack growing, }
+        { so we have to access every page first              }
+        if target_info.system=system_i386_win32 then
+          begin
+             current_asmdata.getjumplabel(again);
+             current_asmdata.getjumplabel(ok);
+             a_label(list,again);
+             list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
+             a_jmp_cond(list,OC_B,ok);
+             list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
+             list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
+             list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
+             a_jmp_always(list,again);
+
+             a_label(list,ok);
+          end;
+{$endif __NOWINPECOFF__}
+        { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
+          by (size div pagesize)*pagesize, otherwise EDI=size.
+          Either way, subtracting EDI from ESP will set ESP to desired final value. }
+        list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
+        { align stack on 4 bytes }
+        list.concat(Taicpu.op_const_reg(A_AND,S_L,aint($fffffff4),NR_ESP));
+        { load destination, don't use a_load_reg_reg, that will add a move instruction
+          that can confuse the reg allocator }
+        list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,NR_EDI));
+
+        { Allocate ESI and load it with source }
+        getcpuregister(list,NR_ESI);
+        a_loadaddr_ref_reg(list,ref,NR_ESI);
+
+        { calculate size }
+        len:=elesize;
+        opsize:=S_B;
+        if (len and 3)=0 then
+         begin
+           opsize:=S_L;
+           len:=len shr 2;
+         end
+        else
+         if (len and 1)=0 then
+          begin
+            opsize:=S_W;
+            len:=len shr 1;
+          end;
+
+        if len>1 then
+          begin
+            if ispowerof2(len, power) then
+              list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_ECX))
+            else
+              list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,NR_ECX));
+          end;
+        list.concat(Taicpu.op_none(A_REP,S_NO));
+        case opsize of
+          S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
+          S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
+          S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
+        end;
+        ungetcpuregister(list,NR_EDI);
+        ungetcpuregister(list,NR_ECX);
+        ungetcpuregister(list,NR_ESI);
+
+        { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
+          that can confuse the reg allocator }
+        list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,destreg));
+      end;
+
+
+    procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
+      begin
+        { Nothing to release }
+      end;
+
+
+    procedure tcg8086.g_exception_reason_save(list : TAsmList; const href : treference);
+      begin
+        if not paramanager.use_fixed_stack then
+          list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
+        else
+         inherited g_exception_reason_save(list,href);
+      end;
+
+
+    procedure tcg8086.g_exception_reason_save_const(list : TAsmList;const href : treference; a: tcgint);
+      begin
+        if not paramanager.use_fixed_stack then
+          list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a))
+        else
+          inherited g_exception_reason_save_const(list,href,a);
+      end;
+
+
+    procedure tcg8086.g_exception_reason_load(list : TAsmList; const href : treference);
+      begin
+        if not paramanager.use_fixed_stack then
+          begin
+            cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
+            list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
+          end
+        else
+          inherited g_exception_reason_load(list,href);
+      end;
+
+
+    procedure tcg8086.g_maybe_got_init(list: TAsmList);
+      var
+        notdarwin: boolean;
+      begin
+        { allocate PIC register }
+        if (cs_create_pic in current_settings.moduleswitches) and
+           (tf_pic_uses_got in target_info.flags) and
+           (pi_needs_got in current_procinfo.flags) then
+          begin
+            notdarwin:=not(target_info.system in [system_i386_darwin,system_i386_iphonesim]);
+            { on darwin, the got register is virtual (and allocated earlier
+              already) }
+            if notdarwin then
+              { ecx could be used in leaf procedures that don't use ecx to pass
+                aparameter }
+              current_procinfo.got:=NR_EBX;
+            if notdarwin { needs testing before it can be enabled for non-darwin platforms
+                and
+               (current_settings.optimizecputype in [cpu_Pentium2,cpu_Pentium3,cpu_Pentium4]) } then
+              begin
+                current_module.requires_ebx_pic_helper:=true;
+                cg.a_call_name_static(list,'fpc_geteipasebx');
+              end
+            else
+              begin
+                { call/pop is faster than call/ret/mov on Core Solo and later
+                  according to Apple's benchmarking -- and all Intel Macs
+                  have at least a Core Solo (furthermore, the i386 - Pentium 1
+                  don't have a return stack buffer) }
+                a_call_name_static(list,current_procinfo.CurrGOTLabel.name);
+                a_label(list,current_procinfo.CurrGotLabel);
+                list.concat(taicpu.op_reg(A_POP,S_L,current_procinfo.got))
+              end;
+            if notdarwin then
+              begin
+                list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_L,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
+                list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil));
+              end;
+          end;
+      end;
+
+
+    procedure tcg8086.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+      {
+      possible calling conventions:
+                    default stdcall cdecl pascal register
+      default(0):      OK     OK    OK     OK       OK
+      virtual(1):      OK     OK    OK     OK       OK(2)
+
+      (0):
+          set self parameter to correct value
+          jmp mangledname
+
+      (1): The wrapper code use %eax to reach the virtual method address
+           set self to correct value
+           move self,%eax
+           mov  0(%eax),%eax ; load vmt
+           jmp  vmtoffs(%eax) ; method offs
+
+      (2): Virtual use values pushed on stack to reach the method address
+           so the following code be generated:
+           set self to correct value
+           push %ebx ; allocate space for function address
+           push %eax
+           mov  self,%eax
+           mov  0(%eax),%eax ; load vmt
+           mov  vmtoffs(%eax),eax ; method offs
+           mov  %eax,4(%esp)
+           pop  %eax
+           ret  0; jmp the address
+
+      }
+
+      procedure getselftoeax(offs: longint);
+        var
+          href : treference;
+          selfoffsetfromsp : longint;
+        begin
+          { mov offset(%esp),%eax }
+          if (procdef.proccalloption<>pocall_register) then
+            begin
+              { framepointer is pushed for nested procs }
+              if procdef.parast.symtablelevel>normal_function_level then
+                selfoffsetfromsp:=2*sizeof(aint)
+              else
+                selfoffsetfromsp:=sizeof(aint);
+              reference_reset_base(href,NR_ESP,selfoffsetfromsp+offs,4);
+              cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+            end;
+        end;
+
+      procedure loadvmttoeax;
+        var
+          href : treference;
+        begin
+          { mov  0(%eax),%eax ; load vmt}
+          reference_reset_base(href,NR_EAX,0,4);
+          cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+        end;
+
+      procedure op_oneaxmethodaddr(op: TAsmOp);
+        var
+          href : treference;
+        begin
+          if (procdef.extnumber=$ffff) then
+            Internalerror(200006139);
+          { call/jmp  vmtoffs(%eax) ; method offs }
+          reference_reset_base(href,NR_EAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4);
+          list.concat(taicpu.op_ref(op,S_L,href));
+        end;
+
+
+      procedure loadmethodoffstoeax;
+        var
+          href : treference;
+        begin
+          if (procdef.extnumber=$ffff) then
+            Internalerror(200006139);
+          { mov vmtoffs(%eax),%eax ; method offs }
+          reference_reset_base(href,NR_EAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4);
+          cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
+        end;
+
+
+      var
+        lab : tasmsymbol;
+        make_global : boolean;
+        href : treference;
+      begin
+        if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
+          Internalerror(200006137);
+        if not assigned(procdef.struct) or
+           (procdef.procoptions*[po_classmethod, po_staticmethod,
+             po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+          Internalerror(200006138);
+        if procdef.owner.symtabletype<>ObjectSymtable then
+          Internalerror(200109191);
+
+        make_global:=false;
+        if (not current_module.is_unit) or
+           create_smartlink or
+           (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
+          make_global:=true;
+
+        if make_global then
+          List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
+        else
+          List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
+
+        { set param1 interface to self  }
+        g_adjust_self_value(list,procdef,ioffset);
+
+        if (po_virtualmethod in procdef.procoptions) and
+            not is_objectpascal_helper(procdef.struct) then
+          begin
+            if (procdef.proccalloption=pocall_register) then
+              begin
+                { case 2 }
+                list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
+                list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
+                getselftoeax(8);
+                loadvmttoeax;
+                loadmethodoffstoeax;
+                { mov %eax,4(%esp) }
+                reference_reset_base(href,NR_ESP,4,4);
+                list.concat(taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
+                { pop  %eax }
+                list.concat(taicpu.op_reg(A_POP,S_L,NR_EAX));
+                { ret  ; jump to the address }
+                list.concat(taicpu.op_none(A_RET,S_L));
+              end
+            else
+              begin
+                { case 1 }
+                getselftoeax(0);
+                loadvmttoeax;
+                op_oneaxmethodaddr(A_JMP);
+              end;
+          end
+        { case 0 }
+        else
+          begin
+            if (target_info.system <> system_i386_darwin) then
+              begin
+                lab:=current_asmdata.RefAsmSymbol(procdef.mangledname);
+                list.concat(taicpu.op_sym(A_JMP,S_NO,lab))
+              end
+            else
+              list.concat(taicpu.op_sym(A_JMP,S_NO,get_darwin_call_stub(procdef.mangledname,false)))
+          end;
+
+        List.concat(Tai_symbol_end.Createname(labelname));
+      end;
+
+
+{ ************* 64bit operations ************ }
+
+    procedure tcg64f386.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
+      begin
+        case op of
+          OP_ADD :
+            begin
+              op1:=A_ADD;
+              op2:=A_ADC;
+            end;
+          OP_SUB :
+            begin
+              op1:=A_SUB;
+              op2:=A_SBB;
+            end;
+          OP_XOR :
+            begin
+              op1:=A_XOR;
+              op2:=A_XOR;
+            end;
+          OP_OR :
+            begin
+              op1:=A_OR;
+              op2:=A_OR;
+            end;
+          OP_AND :
+            begin
+              op1:=A_AND;
+              op2:=A_AND;
+            end;
+          else
+            internalerror(200203241);
+        end;
+      end;
+
+
+    procedure tcg64f386.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
+      var
+        op1,op2 : TAsmOp;
+        tempref : treference;
+      begin
+        if not(op in [OP_NEG,OP_NOT]) then
+          begin
+            get_64bit_ops(op,op1,op2);
+            tempref:=ref;
+            tcgx86(cg).make_simple_ref(list,tempref);
+            list.concat(taicpu.op_ref_reg(op1,S_L,tempref,reg.reglo));
+            inc(tempref.offset,4);
+            list.concat(taicpu.op_ref_reg(op2,S_L,tempref,reg.reghi));
+          end
+        else
+          begin
+            a_load64_ref_reg(list,ref,reg);
+            a_op64_reg_reg(list,op,size,reg,reg);
+          end;
+      end;
+
+
+    procedure tcg64f386.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
+      var
+        op1,op2 : TAsmOp;
+      begin
+        case op of
+          OP_NEG :
+            begin
+              if (regsrc.reglo<>regdst.reglo) then
+                a_load64_reg_reg(list,regsrc,regdst);
+              list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
+              list.concat(taicpu.op_reg(A_NEG,S_L,regdst.reglo));
+              list.concat(taicpu.op_const_reg(A_SBB,S_L,-1,regdst.reghi));
+              exit;
+            end;
+          OP_NOT :
+            begin
+              if (regsrc.reglo<>regdst.reglo) then
+                a_load64_reg_reg(list,regsrc,regdst);
+              list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
+              list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reglo));
+              exit;
+            end;
+        end;
+        get_64bit_ops(op,op1,op2);
+        list.concat(taicpu.op_reg_reg(op1,S_L,regsrc.reglo,regdst.reglo));
+        list.concat(taicpu.op_reg_reg(op2,S_L,regsrc.reghi,regdst.reghi));
+      end;
+
+
+    procedure tcg64f386.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
+      var
+        op1,op2 : TAsmOp;
+      begin
+        case op of
+          OP_AND,OP_OR,OP_XOR:
+            begin
+              cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
+              cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
+            end;
+          OP_ADD, OP_SUB:
+            begin
+              // can't use a_op_const_ref because this may use dec/inc
+              get_64bit_ops(op,op1,op2);
+              list.concat(taicpu.op_const_reg(op1,S_L,aint(lo(value)),reg.reglo));
+              list.concat(taicpu.op_const_reg(op2,S_L,aint(hi(value)),reg.reghi));
+            end;
+          else
+            internalerror(200204021);
+        end;
+      end;
+
+
+    procedure tcg64f386.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
+      var
+        op1,op2 : TAsmOp;
+        tempref : treference;
+      begin
+        tempref:=ref;
+        tcgx86(cg).make_simple_ref(list,tempref);
+        case op of
+          OP_AND,OP_OR,OP_XOR:
+            begin
+              cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
+              inc(tempref.offset,4);
+              cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
+            end;
+          OP_ADD, OP_SUB:
+            begin
+              get_64bit_ops(op,op1,op2);
+              // can't use a_op_const_ref because this may use dec/inc
+              list.concat(taicpu.op_const_ref(op1,S_L,aint(lo(value)),tempref));
+              inc(tempref.offset,4);
+              list.concat(taicpu.op_const_ref(op2,S_L,aint(hi(value)),tempref));
+            end;
+          else
+            internalerror(200204022);
+        end;
+      end;
+
+    procedure create_codegen;
+      begin
+        cg := tcg8086.create;
+        cg64 := tcg64f386.create;
+      end;
+
+end.

+ 60 - 0
compiler/i8086/cpunode.pas

@@ -0,0 +1,60 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl
+
+    Includes the i8086 code generator
+
+    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 cpunode;
+
+{$i fpcdefs.inc}
+
+  interface
+
+  implementation
+
+    uses
+       { generic nodes }
+       ncgbas,
+       ncgld,
+       ncgflw,
+       ncgcnv,
+       ncgmem,
+       ncgmat,
+       ncgcon,
+       ncgcal,
+       ncgset,
+       ncginl,
+       ncgopt,
+       ncgobjc,
+       { to be able to only parts of the generic code,
+         the processor specific nodes must be included
+         after the generic one (FK)
+       }
+       nx86set,
+       nx86con,
+       nx86cnv{,
+
+       n386add,
+       n386cal,
+       n386mem,
+       n386set,
+       n386inl,
+       n386mat}
+       ;
+
+end.

+ 758 - 0
compiler/i8086/cpupara.pas

@@ -0,0 +1,758 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    Generates the argument location information for i386
+
+    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 cpupara;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,
+       aasmtai,aasmdata,cpubase,cgbase,cgutils,
+       symconst,symtype,symsym,symdef,
+       parabase,paramgr;
+
+    type
+       ti386paramanager = class(tparamanager)
+          function param_use_paraloc(const cgpara:tcgpara):boolean;override;
+          function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
+          function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
+          function get_para_align(calloption : tproccalloption):byte;override;
+          function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
+          function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
+          function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
+          { 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.
+          }
+          procedure getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
+          function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
+          function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
+          procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
+          function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara;override;
+       private
+          procedure create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
+          procedure create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parareg,parasize:longint);
+       end;
+
+
+  implementation
+
+    uses
+       cutils,
+       systems,verbose,
+       symtable,
+       defutil;
+
+      const
+        parasupregs : array[0..2] of tsuperregister = (RS_EAX,RS_EDX,RS_ECX);
+
+{****************************************************************************
+                                TI386PARAMANAGER
+****************************************************************************}
+
+    function ti386paramanager.param_use_paraloc(const cgpara:tcgpara):boolean;
+      var
+        paraloc : pcgparalocation;
+      begin
+        if not assigned(cgpara.location) then
+          internalerror(200410102);
+        result:=true;
+        { All locations are LOC_REFERENCE }
+        paraloc:=cgpara.location;
+        while assigned(paraloc) do
+          begin
+            if (paraloc^.loc<>LOC_REFERENCE) then
+              begin
+                result:=false;
+                exit;
+              end;
+            paraloc:=paraloc^.next;
+          end;
+      end;
+
+
+    function ti386paramanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
+      var
+        size: longint;
+      begin
+        if handle_common_ret_in_param(def,pd,result) then
+          exit;
+        case target_info.system of
+          system_i386_win32 :
+            begin
+              case def.typ of
+                recorddef :
+                  begin
+                    { Win32 GCC returns small records in the FUNCTION_RETURN_REG up to 8 bytes in registers.
+
+                      For stdcall and register we follow delphi instead of GCC which returns
+                      only records of a size of 1,2 or 4 bytes in FUNCTION_RETURN_REG }
+                    if ((pd.proccalloption in [pocall_stdcall,pocall_register]) and
+                        (def.size in [1,2,4])) or
+                       ((pd.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
+                        (def.size>0) and
+                        (def.size<=8)) then
+                     begin
+                       result:=false;
+                       exit;
+                     end;
+                  end;
+              end;
+            end;
+          system_i386_freebsd,
+          system_i386_openbsd,
+          system_i386_darwin,
+          system_i386_iphonesim :
+            begin
+              if pd.proccalloption in cdecl_pocalls then
+                begin
+                  case def.typ of
+                    recorddef :
+                      begin
+                        size:=def.size;
+                        if (size>0) and
+                           (size<=8) and
+                           { only if size is a power of 2 }
+                           ((size and (size-1)) = 0) then
+                          begin
+                            result:=false;
+                            exit;
+                          end;
+                      end;
+                    procvardef:
+                      begin
+                        result:=false;
+                        exit;
+                      end;
+                  end;
+              end;
+            end;
+        end;
+        result:=inherited ret_in_param(def,pd);
+      end;
+
+
+    function ti386paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
+      begin
+        result:=false;
+        { var,out,constref always require address }
+        if varspez in [vs_var,vs_out,vs_constref] then
+          begin
+            result:=true;
+            exit;
+          end;
+        { Only vs_const, vs_value here }
+        case def.typ of
+          variantdef :
+            begin
+              { variants are small enough to be passed by value except if
+                required by the windows api
+
+                variants are somethings very delphi/windows specific so do it like
+                windows/delphi (FK)
+              }
+              if ((target_info.system=system_i386_win32) and
+                 (calloption in [pocall_stdcall,pocall_safecall]) and
+                 (varspez=vs_const)) or
+                 (calloption=pocall_register) then
+                result:=true
+              else
+                result:=false;
+            end;
+          formaldef :
+            result:=true;
+          recorddef :
+            begin
+              { Delphi stdcall passes records on the stack for call by value }
+              if (target_info.system=system_i386_win32) and
+                 (calloption=pocall_stdcall) and
+                 (varspez=vs_value) then
+                result:=false
+              else
+                result:=
+                  (not(calloption in (cdecl_pocalls)) and
+                   (def.size>sizeof(aint))) or
+                  (((calloption = pocall_mwpascal) or (target_info.system=system_i386_wince)) and
+                   (varspez=vs_const));
+            end;
+          arraydef :
+            begin
+              { array of const values are pushed on the stack as
+                well as dyn. arrays }
+              if (calloption in cdecl_pocalls) then
+                result:=not(is_array_of_const(def) or
+                        is_dynamic_array(def))
+              else
+                begin
+                  result:=(
+                           (tarraydef(def).highrange>=tarraydef(def).lowrange) and
+                           (def.size>sizeof(aint))
+                          ) or
+                          is_open_array(def) or
+                          is_array_of_const(def) or
+                          is_array_constructor(def);
+                end;
+            end;
+          objectdef :
+            result:=is_object(def);
+          stringdef :
+            result:= (tstringdef(def).stringtype in [st_shortstring,st_longstring]);
+          procvardef :
+            result:=not(calloption in cdecl_pocalls) and not tprocvardef(def).is_addressonly;
+          setdef :
+            result:=not(calloption in cdecl_pocalls) and (not is_smallset(def));
+        end;
+      end;
+
+
+    function ti386paramanager.get_para_align(calloption : tproccalloption):byte;
+      begin
+        if calloption=pocall_oldfpccall then
+          begin
+            if target_info.system in [system_i386_go32v2,system_i386_watcom] then
+              result:=2
+            else
+              result:=4;
+          end
+        else
+          result:=std_param_align;
+      end;
+
+
+    function ti386paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
+      begin
+        case calloption of
+          pocall_internproc :
+            result:=[];
+          pocall_register,
+          pocall_safecall,
+          pocall_stdcall,
+          pocall_cdecl,
+          pocall_cppdecl,
+          pocall_mwpascal :
+            result:=[RS_EAX,RS_EDX,RS_ECX];
+          pocall_far16,
+          pocall_pascal,
+          pocall_oldfpccall :
+            result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX];
+          else
+            internalerror(200309071);
+        end;
+      end;
+
+
+    function ti386paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=[0..first_fpu_imreg-1];
+      end;
+
+
+    function ti386paramanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=[0..first_mm_imreg-1];
+      end;
+
+
+    procedure ti386paramanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
+      var
+        paraloc : pcgparalocation;
+        def : tdef;
+      begin
+        def:=tparavarsym(pd.paras[nr-1]).vardef;
+        cgpara.reset;
+        cgpara.size:=def_cgsize(def);
+        cgpara.intsize:=tcgsize2size[cgpara.size];
+        cgpara.alignment:=get_para_align(pd.proccalloption);
+        cgpara.def:=def;
+        paraloc:=cgpara.add_location;
+        with paraloc^ do
+         begin
+           size:=OS_INT;
+           if pd.proccalloption=pocall_register then
+             begin
+               if (nr<=length(parasupregs)) then
+                 begin
+                   if nr=0 then
+                     internalerror(200309271);
+                   loc:=LOC_REGISTER;
+                   register:=newreg(R_INTREGISTER,parasupregs[nr-1],R_SUBWHOLE);
+                 end
+               else
+                 begin
+                   loc:=LOC_REFERENCE;
+                   reference.index:=NR_STACK_POINTER_REG;
+                   { the previous parameters didn't take up room in memory }
+                   reference.offset:=sizeof(aint)*(nr-length(parasupregs)-1)
+                 end;
+             end
+           else
+             begin
+               loc:=LOC_REFERENCE;
+               reference.index:=NR_STACK_POINTER_REG;
+               reference.offset:=sizeof(aint)*nr;
+             end;
+          end;
+      end;
+
+
+    function  ti386paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara;
+      var
+        retcgsize  : tcgsize;
+        paraloc : pcgparalocation;
+        sym: tfieldvarsym;
+        usedef: tdef;
+        handled: boolean;
+      begin
+        if not assigned(forcetempdef) then
+          usedef:=p.returndef
+        else
+          usedef:=forcetempdef;
+        { on darwin/i386, if a record has only one field and that field is a
+          single or double, it has to be returned like a single/double }
+        if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+           ((usedef.typ=recorddef) or
+            is_object(usedef)) and
+           tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(sym) and
+           (sym.vardef.typ=floatdef) and
+           (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then
+          usedef:=sym.vardef;
+
+        handled:=set_common_funcretloc_info(p,usedef,retcgsize,result);
+        { normally forcetempdef is passed straight through to
+          set_common_funcretloc_info and that one will correctly determine whether
+          the location is a temporary one, but that doesn't work here because we
+          sometimes have to change the type }
+        result.temporary:=assigned(forcetempdef);
+        if handled then
+          exit;
+
+        { darwin/x86 requires that results < sizeof(aint) are sign/zero
+          extended to sizeof(aint) }
+        if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+           (side=calleeside) and
+           (result.intsize>0) and
+           (result.intsize<sizeof(aint)) then
+          begin
+            result.def:=sinttype;
+            result.intsize:=sizeof(aint);
+            retcgsize:=OS_SINT;
+            result.size:=retcgsize;
+          end;
+
+        { Return in FPU register? }
+        if result.def.typ=floatdef then
+          begin
+            paraloc:=result.add_location;
+            paraloc^.loc:=LOC_FPUREGISTER;
+            paraloc^.register:=NR_FPU_RESULT_REG;
+            paraloc^.size:=retcgsize;
+          end
+        else
+         { Return in register }
+          begin
+            paraloc:=result.add_location;
+            paraloc^.loc:=LOC_REGISTER;
+            if retcgsize in [OS_64,OS_S64] then
+             begin
+               { low 32bits }
+               if side=callerside then
+                 paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
+               else
+                 paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
+               paraloc^.size:=OS_32;
+
+               { high 32bits }
+               paraloc:=result.add_location;
+               paraloc^.loc:=LOC_REGISTER;
+               if side=callerside then
+                 paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
+               else
+                 paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
+               paraloc^.size:=OS_32;
+             end
+            else
+             begin
+               paraloc^.size:=retcgsize;
+               if side=callerside then
+                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
+               else
+                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
+             end;
+          end;
+      end;
+
+
+    procedure ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
+      var
+        i  : integer;
+        hp : tparavarsym;
+        paradef : tdef;
+        paraloc : pcgparalocation;
+        l,
+        paralen,
+        varalign   : longint;
+        paraalign  : shortint;
+        pushaddr   : boolean;
+        paracgsize : tcgsize;
+      begin
+        paraalign:=get_para_align(p.proccalloption);
+        { we push Flags and CS as long
+          to cope with the IRETD
+          and we save 6 register + 4 selectors }
+        if po_interrupt in p.procoptions then
+          inc(parasize,8+6*4+4*2);
+        { Offset is calculated like:
+           sub esp,12
+           mov [esp+8],para3
+           mov [esp+4],para2
+           mov [esp],para1
+           call function
+          That means for pushes the para with the
+          highest offset (see para3) needs to be pushed first
+        }
+        if p.proccalloption in pushleftright_pocalls then
+          i:=paras.count-1
+        else
+          i:=0;
+        while ((p.proccalloption in pushleftright_pocalls) and (i>=0)) or
+              (not(p.proccalloption in pushleftright_pocalls) and (i<=paras.count-1)) do
+          begin
+            hp:=tparavarsym(paras[i]);
+            paradef:=hp.vardef;
+            pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption);
+            if pushaddr then
+              begin
+                paralen:=sizeof(aint);
+                paracgsize:=OS_ADDR;
+                paradef:=getpointerdef(paradef);
+              end
+            else
+              begin
+                paralen:=push_size(hp.varspez,paradef,p.proccalloption);
+                { darwin/x86 requires that parameters < sizeof(aint) are sign/ }
+                { zero extended to sizeof(aint)                                }
+                if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+                   (side = callerside) and
+                   (paralen > 0) and
+                   (paralen < sizeof(aint)) then
+                  begin
+                    paralen:=sizeof(aint);
+                    paracgsize:=OS_SINT;
+                    paradef:=sinttype;
+                  end
+                else
+                  paracgsize:=def_cgsize(paradef);
+              end;
+            hp.paraloc[side].reset;
+            hp.paraloc[side].size:=paracgsize;
+            hp.paraloc[side].intsize:=paralen;
+            hp.paraloc[side].def:=paradef;
+            hp.paraloc[side].Alignment:=paraalign;
+            { Copy to stack? }
+            if (paracgsize=OS_NO) or
+               (use_fixed_stack) then
+              begin
+                paraloc:=hp.paraloc[side].add_location;
+                paraloc^.loc:=LOC_REFERENCE;
+                paraloc^.size:=paracgsize;
+                if side=callerside then
+                  paraloc^.reference.index:=NR_STACK_POINTER_REG
+                else
+                  paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
+
+                { don't let push_size return 16, because then we can    }
+                { read past the end of the heap since the value is only }
+                { 10 bytes long (JM)                                    }
+                if (paracgsize = OS_F80) and
+                   (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
+                  paralen:=16;
+                paraloc^.reference.offset:=parasize;
+                if side=calleeside then
+                  inc(paraloc^.reference.offset,target_info.first_parm_offset);
+                parasize:=align(parasize+paralen,varalign);
+              end
+            else
+              begin
+                if paralen=0 then
+                  internalerror(200501163);
+                while (paralen>0) do
+                  begin
+                    paraloc:=hp.paraloc[side].add_location;
+                    paraloc^.loc:=LOC_REFERENCE;
+                    { single and double need a single location }
+                    if (paracgsize in [OS_F64,OS_F32]) then
+                      begin
+                        paraloc^.size:=paracgsize;
+                        l:=paralen;
+                      end
+                    else
+                      begin
+                        { We can allocate at maximum 32 bits per location }
+                        if paralen>sizeof(aint) then
+                          l:=sizeof(aint)
+                        else
+                          l:=paralen;
+                        paraloc^.size:=int_cgsize(l);
+                      end;
+                    if (side=callerside) or
+                       (po_nostackframe in p.procoptions) then
+                      paraloc^.reference.index:=NR_STACK_POINTER_REG
+                    else
+                      paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                    varalign:=used_align(size_2_align(l),paraalign,paraalign);
+                    paraloc^.reference.offset:=parasize;
+                    if side=calleeside then
+                      if not(po_nostackframe in p.procoptions) then
+                        inc(paraloc^.reference.offset,target_info.first_parm_offset)
+                      else
+                        { return addres }
+                        inc(paraloc^.reference.offset,4);
+                    parasize:=align(parasize+l,varalign);
+                    dec(paralen,l);
+                  end;
+              end;
+            if p.proccalloption in pushleftright_pocalls then
+              dec(i)
+            else
+              inc(i);
+          end;
+      end;
+
+
+    procedure ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
+                                                            var parareg,parasize:longint);
+      var
+        hp : tparavarsym;
+        paradef : tdef;
+        paraloc : pcgparalocation;
+        paracgsize : tcgsize;
+        i : integer;
+        l,
+        paralen,
+        varalign : longint;
+        pushaddr : boolean;
+        paraalign : shortint;
+        pass : byte;
+      begin
+        if paras.count=0 then
+          exit;
+        paraalign:=get_para_align(p.proccalloption);
+
+        { clean up here so we can later detect properly if a parameter has been
+          assigned or not
+        }
+        for i:=0 to paras.count-1 do
+          tparavarsym(paras[i]).paraloc[side].reset;
+        { Register parameters are assigned from left to right,
+          stack parameters from right to left so assign first the
+          register parameters in a first pass, in the second
+          pass all unhandled parameters are done }
+        for pass:=1 to 2 do
+          begin
+            if pass=1 then
+              i:=0
+            else
+              i:=paras.count-1;
+            while true do
+              begin
+                hp:=tparavarsym(paras[i]);
+                paradef:=hp.vardef;
+                if not(assigned(hp.paraloc[side].location)) then
+                  begin
+                    pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
+                    if pushaddr then
+                      begin
+                        paralen:=sizeof(aint);
+                        paracgsize:=OS_ADDR;
+                        paradef:=getpointerdef(paradef);
+                      end
+                    else
+                      begin
+                        paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
+                        paracgsize:=def_cgsize(hp.vardef);
+                      end;
+                    hp.paraloc[side].size:=paracgsize;
+                    hp.paraloc[side].intsize:=paralen;
+                    hp.paraloc[side].Alignment:=paraalign;
+                    hp.paraloc[side].def:=paradef;
+                    {
+                      EAX
+                      EDX
+                      ECX
+                      Stack
+                      Stack
+
+                      64bit values,floats,arrays and records are always
+                      on the stack.
+
+                      In case of po_delphi_nested_cc, the parent frame pointer
+                      is also always passed on the stack.
+                    }
+                    if (parareg<=high(parasupregs)) and
+                       (paralen<=sizeof(aint)) and
+                       (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
+                        pushaddr) and
+                       (not(vo_is_parentfp in hp.varoptions) or
+                        not(po_delphi_nested_cc in p.procoptions)) then
+                      begin
+                        if pass=1 then
+                          begin
+                            paraloc:=hp.paraloc[side].add_location;
+                            paraloc^.size:=paracgsize;
+                            paraloc^.loc:=LOC_REGISTER;
+                            paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
+                            inc(parareg);
+                          end;
+                      end
+                    else
+                      if pass=2 then
+                        begin
+                          { Copy to stack? }
+                          if (use_fixed_stack) or
+                             (paracgsize=OS_NO) then
+                            begin
+                              paraloc:=hp.paraloc[side].add_location;
+                              paraloc^.loc:=LOC_REFERENCE;
+                              paraloc^.size:=paracgsize;
+                              if side=callerside then
+                                paraloc^.reference.index:=NR_STACK_POINTER_REG
+                              else
+                                paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                              varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
+                              paraloc^.reference.offset:=parasize;
+                              if side=calleeside then
+                                inc(paraloc^.reference.offset,target_info.first_parm_offset);
+                              parasize:=align(parasize+paralen,varalign);
+                            end
+                          else
+                            begin
+                              if paralen=0 then
+                                internalerror(200501163);
+                              while (paralen>0) do
+                                begin
+                                  paraloc:=hp.paraloc[side].add_location;
+                                  paraloc^.loc:=LOC_REFERENCE;
+                                  { Extended and double need a single location }
+                                  if (paracgsize in [OS_F64,OS_F32]) then
+                                    begin
+                                      paraloc^.size:=paracgsize;
+                                      l:=paralen;
+                                    end
+                                  else
+                                    begin
+                                      { We can allocate at maximum 32 bits per location }
+                                      if paralen>sizeof(aint) then
+                                        l:=sizeof(aint)
+                                      else
+                                        l:=paralen;
+                                      paraloc^.size:=int_cgsize(l);
+                                    end;
+                                  if side=callerside then
+                                    paraloc^.reference.index:=NR_STACK_POINTER_REG
+                                  else
+                                    paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                                  varalign:=used_align(size_2_align(l),paraalign,paraalign);
+                                  paraloc^.reference.offset:=parasize;
+                                  if side=calleeside then
+                                    inc(paraloc^.reference.offset,target_info.first_parm_offset);
+                                  parasize:=align(parasize+l,varalign);
+                                  dec(paralen,l);
+                                end;
+                            end;
+                        end;
+                  end;
+                case pass of
+                  1:
+                    begin
+                      if i=paras.count-1 then
+                        break;
+                      inc(i);
+                    end;
+                  2:
+                    begin
+                      if i=0 then
+                        break;
+                      dec(i);
+                    end;
+                end;
+              end;
+          end;
+      end;
+
+
+    function ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
+      var
+        parasize,
+        parareg : longint;
+      begin
+        parasize:=0;
+        parareg:=0;
+        case p.proccalloption of
+          pocall_register :
+            create_register_paraloc_info(p,side,p.paras,parareg,parasize);
+          pocall_internproc :
+            begin
+              { Use default calling }
+{$warnings off}
+              if (pocall_default=pocall_register) then
+                create_register_paraloc_info(p,side,p.paras,parareg,parasize)
+              else
+                create_stdcall_paraloc_info(p,side,p.paras,parasize);
+{$warnings on}
+            end;
+          else
+            create_stdcall_paraloc_info(p,side,p.paras,parasize);
+        end;
+        create_funcretloc_info(p,side);
+        result:=parasize;
+      end;
+
+
+    function ti386paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
+      var
+        parasize : longint;
+      begin
+        parasize:=0;
+        { calculate the registers for the normal parameters }
+        create_stdcall_paraloc_info(p,callerside,p.paras,parasize);
+        { append the varargs }
+        create_stdcall_paraloc_info(p,callerside,varargspara,parasize);
+        result:=parasize;
+      end;
+
+
+    procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
+      begin
+        { Never a need for temps when value is pushed (calls inside parameters
+          will simply allocate even more stack space for their parameters) }
+        if not(use_fixed_stack) then
+          can_use_final_stack_loc:=true;
+        inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
+      end;
+
+
+begin
+   paramanager:=ti386paramanager.create;
+end.

+ 109 - 0
compiler/i8086/cpupi.pas

@@ -0,0 +1,109 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    This unit contains the CPU specific part of tprocinfo
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{ This unit contains the CPU specific part of tprocinfo. }
+unit cpupi;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       psub,procinfo,aasmdata;
+
+    type
+       ti386procinfo = class(tcgprocinfo)
+         constructor create(aparent:tprocinfo);override;
+         procedure set_first_temp_offset;override;
+         function calc_stackframe_size:longint;override;
+         procedure generate_parameter_info;override;
+         procedure allocate_got_register(list: tasmlist);override;
+       end;
+
+
+  implementation
+
+    uses
+      cutils,
+      systems,globals,globtype,
+      cgobj,tgobj,paramgr,
+      cpubase,
+      cgutils,
+      symconst;
+
+    constructor ti386procinfo.create(aparent:tprocinfo);
+      begin
+        inherited create(aparent);
+        got:=NR_EBX;
+      end;
+
+
+    procedure ti386procinfo.set_first_temp_offset;
+      begin
+        if paramanager.use_fixed_stack then
+          begin
+            if not(po_assembler in procdef.procoptions) and
+               (tg.direction > 0) then
+              tg.setfirsttemp(tg.direction*maxpushedparasize);
+            if (tg.direction < 0) and
+               not(po_nostackframe in procdef.procoptions) then
+              { compensate for the return address and the "pushl %ebp" }
+              tg.setalignmentmismatch(sizeof(pint)*2);
+          end;
+      end;
+
+
+    function ti386procinfo.calc_stackframe_size:longint;
+      begin
+        { align to 4 bytes at least
+          otherwise all those subl $2,%esp are meaningless PM }
+        if target_info.stackalign<=4 then
+          result:=Align(tg.direction*tg.lasttemp,min(current_settings.alignment.localalignmax,4))
+        else
+          { aligned during stack frame allocation, because also depends number
+            of saved registers }
+          result:=tg.direction*tg.lasttemp+maxpushedparasize;
+      end;
+
+
+    procedure ti386procinfo.generate_parameter_info;
+      begin
+        inherited generate_parameter_info;
+        { Para_stack_size is only used to determine how many bytes to remove }
+        { from the stack at the end of the procedure (in the "ret $xx").     }
+        { If the stack is fixed, nothing has to be removed by the callee     }
+        if paramanager.use_fixed_stack then
+          para_stack_size := 0;
+      end;
+
+    procedure ti386procinfo.allocate_got_register(list: tasmlist);
+      begin
+        if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+           (cs_create_pic in current_settings.moduleswitches) then
+          begin
+            got := cg.getaddressregister(list);
+          end;
+      end;
+
+begin
+   cprocinfo:=ti386procinfo;
+end.

+ 88 - 0
compiler/i8086/cputarg.pas

@@ -0,0 +1,88 @@
+{
+    Copyright (c) 2001-2002 by Peter Vreman
+
+    Includes the i8086 dependent target units
+
+    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 cputarg;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+      systems { prevent a syntax error when nothing is included }
+
+{**************************************
+             Targets
+**************************************}
+
+    {$ifndef NOTARGETMSDOS}
+      ,t_msdos
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAG386ATT}
+//      ,agx86att
+    {$endif}
+    {$ifndef NOAG386NSM}
+      ,agx86nsm
+    {$endif}
+    {$ifndef NOAG386INT}
+//      ,agx86int
+    {$endif}
+
+//      ,ogcoff
+//      ,ogelf
+//      ,ogmacho
+//      ,cpuelf
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRa8086Int}
+       ,ra8086int
+  {$endif NoRa8086Int}
+  {$ifndef NoRa8086Att}
+       ,ra8086att
+  {$endif NoRa8086Att}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoCFIDwarf}
+      ,cfidwarf
+  {$endif NoCFIDwarf}
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+
+      ;
+
+end.

+ 203 - 0
compiler/i8086/hlcgcpu.pas

@@ -0,0 +1,203 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains routines to create a pass-through high-level code
+    generator. This is used by most regular code generators.
+
+    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 hlcgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    aasmdata,
+    symtype,symdef,parabase,
+    cgbase,cgutils,
+    hlcgobj, hlcgx86;
+
+
+  type
+    thlcgcpu = class(thlcgx86)
+     protected
+      procedure gen_loadfpu_loc_cgpara(list: TAsmList; size: tdef; const l: tlocation; const cgpara: tcgpara; locintsize: longint); override;
+     public
+      procedure g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister); override;
+      procedure g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation); override;
+    end;
+
+  procedure create_hlcodegen;
+
+implementation
+
+  uses
+    globtype,verbose,
+    paramgr,
+    cpubase,tgobj,cgobj,cgcpu;
+
+  { thlcgcpu }
+
+  procedure thlcgcpu.gen_loadfpu_loc_cgpara(list: TAsmList; size: tdef; const l: tlocation; const cgpara: tcgpara; locintsize: longint);
+    var
+      locsize : tcgsize;
+      tmploc : tlocation;
+      href   : treference;
+      stacksize   : longint;
+    begin
+      if not(l.size in [OS_32,OS_S32,OS_64,OS_S64,OS_128,OS_S128]) then
+        locsize:=l.size
+      else
+        locsize:=int_float_cgsize(tcgsize2size[l.size]);
+      case l.loc of
+        LOC_FPUREGISTER,
+        LOC_CFPUREGISTER:
+          begin
+            case cgpara.location^.loc of
+              LOC_REFERENCE:
+                begin
+                  stacksize:=align(locintsize,cgpara.alignment);
+                  if (not paramanager.use_fixed_stack) and
+                     (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
+                    begin
+                      cg.g_stackpointer_alloc(list,stacksize);
+                      reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
+                    end
+                  else
+                    reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
+                  cg.a_loadfpu_reg_ref(list,locsize,locsize,l.register,href);
+                end;
+              LOC_FPUREGISTER:
+                begin
+                  cg.a_loadfpu_reg_reg(list,locsize,cgpara.location^.size,l.register,cgpara.location^.register);
+                end;
+              { can happen if a record with only 1 "single field" is
+                returned in a floating point register and then is directly
+                passed to a regcall parameter }
+              LOC_REGISTER:
+                begin
+                  tmploc:=l;
+                  location_force_mem(list,tmploc,size);
+                  case locsize of
+                    OS_F32:
+                      tmploc.size:=OS_32;
+                    OS_F64:
+                      tmploc.size:=OS_64;
+                    else
+                      internalerror(2010053116);
+                  end;
+                  cg.a_load_loc_cgpara(list,tmploc,cgpara);
+                  location_freetemp(list,tmploc);
+                end
+              else
+                internalerror(2010053003);
+            end;
+          end;
+        LOC_MMREGISTER,
+        LOC_CMMREGISTER:
+          begin
+            case cgpara.location^.loc of
+              LOC_REFERENCE:
+                begin
+                  { can't use TCGSize2Size[l.size], because the size of an
+                    80 bit extended parameter can be either 10 or 12 bytes }
+                  stacksize:=align(locintsize,cgpara.alignment);
+                  if (not paramanager.use_fixed_stack) and
+                     (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
+                    begin
+                      cg.g_stackpointer_alloc(list,stacksize);
+                      reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
+                    end
+                  else
+                    reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
+                  cg.a_loadmm_reg_ref(list,locsize,locsize,l.register,href,mms_movescalar);
+                end;
+              LOC_FPUREGISTER:
+                begin
+                  tmploc:=l;
+                  location_force_mem(list,tmploc,size);
+                  cg.a_loadfpu_ref_cgpara(list,tmploc.size,tmploc.reference,cgpara);
+                  location_freetemp(list,tmploc);
+                end;
+              else
+                internalerror(2010053004);
+            end;
+          end;
+        LOC_REFERENCE,
+        LOC_CREFERENCE :
+          begin
+            case cgpara.location^.loc of
+              LOC_REFERENCE:
+                begin
+                  stacksize:=align(locintsize,cgpara.alignment);
+                  if (not paramanager.use_fixed_stack) and
+                     (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
+                    cg.a_load_ref_cgpara(list,locsize,l.reference,cgpara)
+                  else
+                    begin
+                      reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
+                      cg.g_concatcopy(list,l.reference,href,stacksize);
+                    end;
+                end;
+              LOC_FPUREGISTER:
+                begin
+                  cg.a_loadfpu_ref_cgpara(list,locsize,l.reference,cgpara);
+                end;
+              else
+                internalerror(2010053005);
+            end;
+          end;
+        else
+          internalerror(2002042430);
+      end;
+    end;
+
+
+  procedure thlcgcpu.g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister);
+    begin
+      if paramanager.use_fixed_stack then
+        begin
+          inherited;
+          exit;
+        end;
+      tcg8086(cg).g_copyvaluepara_openarray(list,ref,lenloc,arrdef.elesize,destreg);
+    end;
+
+
+  procedure thlcgcpu.g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation);
+    begin
+      if paramanager.use_fixed_stack then
+        begin
+          inherited;
+          exit;
+        end;
+      tcg8086(cg).g_releasevaluepara_openarray(list,l);
+    end;
+
+
+  procedure create_hlcodegen;
+    begin
+      hlcg:=thlcgcpu.create;
+      create_codegen;
+    end;
+
+
+
+end.

+ 59 - 0
compiler/i8086/ra8086att.pas

@@ -0,0 +1,59 @@
+{
+    Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
+
+    Does the parsing for the i8086 GNU AS styled inline assembler.
+
+    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 ra8086att;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      rax86att;
+
+    type
+      ti8086attreader = class(tx86attreader)
+      end;
+
+
+  implementation
+
+    uses
+      rabase,systems;
+
+const
+  asmmode_i8086_att_info : tasmmodeinfo =
+          (
+            id    : asmmode_i8086_att;
+            idtxt : 'ATT';
+            casmreader : ti8086attreader;
+          );
+
+  asmmode_i8086_standard_info : tasmmodeinfo =
+          (
+            id    : asmmode_standard;
+            idtxt : 'STANDARD';
+            casmreader : ti8086attreader;
+          );
+
+initialization
+  RegisterAsmMode(asmmode_i8086_att_info);
+  RegisterAsmMode(asmmode_i8086_standard_info);
+end.

+ 74 - 0
compiler/i8086/ra8086int.pas

@@ -0,0 +1,74 @@
+{
+    Copyright (c) 1998-2006 by Carl Eric Codere and Peter Vreman
+
+    Does the parsing for the i8086 intel styled inline assembler.
+
+    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 ra8086int;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      rax86int;
+
+    type
+      ti8086intreader = class(tx86intreader)
+        // procedure handleopcode;override;
+      end;
+
+
+  implementation
+
+    uses
+      rabase,systems,rax86,aasmcpu;
+
+(*
+    procedure ti386intreader.handleopcode;
+      var
+        instr : Tx86Instruction;
+      begin
+        instr:=Tx86Instruction.Create(Tx86Operand);
+        instr.OpOrder:=op_att;
+        BuildOpcode(instr);
+        instr.AddReferenceSizes;
+        instr.SetInstructionOpsize;
+        {
+        instr.CheckOperandSizes;
+        }
+        instr.ConcatInstruction(curlist);
+        instr.Free;
+      end;
+*)
+
+{*****************************************************************************
+                               Initialize
+*****************************************************************************}
+
+const
+  asmmode_i8086_intel_info : tasmmodeinfo =
+          (
+            id    : asmmode_i8086_intel;
+            idtxt : 'INTEL';
+            casmreader : ti8086intreader;
+          );
+
+begin
+  RegisterAsmMode(asmmode_i8086_intel_info);
+end.

+ 71 - 0
compiler/i8086/rgcpu.pas

@@ -0,0 +1,71 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the i386 specific class for the register
+    allocator
+
+    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 rgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      cpubase,
+      cpuinfo,
+      aasmbase,aasmtai,aasmdata,
+      cclasses,globtype,cgbase,rgobj,rgx86;
+
+    type
+       trgcpu = class(trgx86)
+          procedure add_constraints(reg:Tregister);override;
+       end;
+
+implementation
+
+    uses
+       systems,
+       verbose;
+
+    const
+       { This value is used in tsaved. If the array value is equal
+         to this, then this means that this register is not used.}
+       reg_not_saved = $7fffffff;
+
+{************************************************************************
+                                 trgcpu
+*************************************************************************}
+
+    procedure trgcpu.add_constraints(reg:Tregister);
+      var
+        supreg : tsuperregister;
+      begin
+        if getsubreg(reg) in [R_SUBL,R_SUBH] then
+          begin
+            { Some registers have no 8-bit subregister }
+            supreg:=getsupreg(reg);
+            add_edge(supreg,RS_SI);
+            add_edge(supreg,RS_DI);
+            add_edge(supreg,RS_BP);
+          end;
+      end;
+
+
+end.

+ 2 - 0
compiler/systems.inc

@@ -66,6 +66,8 @@
             ,asmmode_x86_64_intel
             ,asmmode_x86_64_att
             ,asmmode_avr_gas
+            ,asmmode_i8086_intel
+            ,asmmode_i8086_att
        );
 
      (* IMPORTANT NOTE:

+ 13 - 0
compiler/x86/cpubase.pas

@@ -276,6 +276,11 @@ uses
     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
 
+{$ifdef i8086}
+    { returns the next virtual register }
+    function GetNextReg(const r : TRegister) : TRegister;
+{$endif i8086}
+
 implementation
 
     uses
@@ -526,4 +531,12 @@ implementation
       end;
 
 
+{$ifdef i8086}
+    function GetNextReg(const r: TRegister): TRegister;
+      begin
+        result:=TRegister(longint(r)+1);
+      end;
+{$endif i8086}
+
+
 end.

+ 3 - 0
compiler/x86/rax86att.pas

@@ -352,6 +352,9 @@ Implementation
 {$ifdef i386}
                   if actasmpattern='GOT' then
 {$endif i386}
+{$ifdef i8086}
+                  if actasmpattern='GOT' then
+{$endif i8086}
                     begin
                       oper.opr.ref.refaddr:=addr_pic;
                       consume(AS_ID);