Browse Source

* i8086 huge memory model threadvar code generation fixes

git-svn-id: trunk@31516 -
nickysn 10 years ago
parent
commit
2087290802
1 changed files with 77 additions and 5 deletions
  1. 77 5
      compiler/i8086/n8086ld.pas

+ 77 - 5
compiler/i8086/n8086ld.pas

@@ -46,11 +46,13 @@ interface
 implementation
 
     uses
-      globals,aasmdata,defutil,
-      symconst,symcpu,
+      globals,verbose,aasmdata,defutil,
+      symconst,symdef,symtable,symcpu,
       nld,
       cgbase,cgobj,cgutils,
-      cpubase,cpuinfo;
+      hlcgobj,
+      cpubase,cpuinfo,
+      parabase,paramgr;
 
 {*****************************************************************************
                             TI8086LOADNODE
@@ -98,6 +100,12 @@ implementation
         refsym: TAsmSymbol;
         segreg: TRegister;
         newsize: TCgSize;
+        norelocatelab: TAsmLabel;
+        endrelocatelab: TAsmLabel;
+        pvd: tdef;
+        paraloc1 : tcgpara;
+        hregister: TRegister;
+        href: treference;
       begin
         if current_settings.x86memorymodel=mm_huge then
           begin
@@ -114,8 +122,72 @@ implementation
                   { Thread variable }
                   else if (vo_is_thread_var in gvs.varoptions) then
                     begin
-                      inherited pass_generate_code;
-                      exit;
+                      if (cs_compilesystem in current_settings.moduleswitches) then
+                        begin
+                          inherited pass_generate_code;
+                          exit;
+                        end;
+
+                      { we don't know the size of all arrays }
+                      newsize:=def_cgsize(resultdef);
+                      { alignment is overridden per case below }
+                      location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment);
+
+                      {
+                        Thread var loading is optimized to first check if
+                        a relocate function is available. When the function
+                        is available it is called to retrieve the address.
+                        Otherwise the address is loaded with the symbol
+
+                        The code needs to be in the order to first handle the
+                        call and then the address load to be sure that the
+                        register that is used for returning is the same (PFV)
+                      }
+                      current_asmdata.getjumplabel(norelocatelab);
+                      current_asmdata.getjumplabel(endrelocatelab);
+                      { make sure hregister can't allocate the register necessary for the parameter }
+                      pvd:=search_system_type('TRELOCATETHREADVARHANDLER').typedef;
+                      if pvd.typ<>procvardef then
+                        internalerror(2012120901);
+                      paraloc1.init;
+                      paramanager.getintparaloc(current_asmdata.CurrAsmList,tprocvardef(pvd),1,paraloc1);
+                      hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pvd);
+                      segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
+                      reference_reset_symbol(segref,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0,0);
+                      segref.refaddr:=addr_seg;
+                      cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
+                      reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0,pvd.size);
+                      href.segment:=segreg;
+                      hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,pvd,pvd,href,hregister);
+                      hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,pvd,OC_EQ,0,hregister,norelocatelab);
+                      { don't save the allocated register else the result will be destroyed later }
+                      if not(vo_is_weak_external in gvs.varoptions) then
+                        reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname),0,sizeof(pint))
+                      else
+                        reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),0,sizeof(pint));
+                      cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
+                      paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
+                      paraloc1.done;
+                      cg.allocallcpuregisters(current_asmdata.CurrAsmList);
+                      cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
+                      cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
+                      cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
+                      cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
+                      hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
+                      cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
+                      cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
+                      { no relocation needed, load the address of the variable only, the
+                        layout of a threadvar is (4 bytes pointer):
+                          0 - Threadvar index
+                          4 - Threadvar value in single threading }
+                      if not(vo_is_weak_external in gvs.varoptions) then
+                        reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname),sizeof(pint),sizeof(pint))
+                      else
+                        reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),sizeof(pint),sizeof(pint));
+                      hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,voidpointertype,href,hregister);
+                      cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
+                      hlcg.reference_reset_base(location.reference,voidpointertype,hregister,0,location.reference.alignment);
                     end
                   { Normal (or external) variable }
                   else