{ Copyright (c) 2002-2014 by Florian Klaempfl Generate i8086 assembler for load nodes 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 n8086ld; {$i fpcdefs.inc} interface uses globtype, symsym,symtype, node,ncgld,nx86ld,aasmbase; type { ti8086loadnode } ti8086loadnode = class(tx86loadnode) protected procedure generate_nested_access(vs: tsym); override; procedure generate_absaddr_access(vs: tabsolutevarsym); override; procedure generate_threadvar_access(gvs: tstaticvarsym); override; public procedure pass_generate_code;override; end; implementation uses globals,verbose,aasmdata,defutil, symconst,symdef,symtable,symcpu, nld, cgbase,cgobj,cgutils, hlcgobj, cpubase,cpuinfo, parabase,paramgr; {***************************************************************************** TI8086LOADNODE *****************************************************************************} procedure ti8086loadnode.generate_nested_access(vs: tsym); begin inherited; { the parentfp pointer is always a near pointer (this is turbo pascal compatible) regardless of memory model, so we need to set the segment manually. todo: once the far data memory models are fully implemented, the parentfp type should be changed to a near 'ss' pointer in all memory models and then this code can be removed. But this can only happen after: 1) all calls to a_loadaddr_ref_reg go through the high level code generator 2) a_loadaddr_ref_reg in the low level code generator stops using the presence of a segment in the source reference to determine the destination reg size 3) make_simple_ref is updated to remove unnecessary segment prefixes 4) hlcg.reference_reset_base is updated to set the segment on near_ss pointers } if (left.nodetype=loadparentfpn) and (current_settings.x86memorymodel in x86_far_data_models) then location.reference.segment:=NR_SS; end; procedure ti8086loadnode.generate_absaddr_access(vs: tabsolutevarsym); begin if tcpuabsolutevarsym(symtableentry).absseg then begin location.reference.segment:=cg.getintregister(current_asmdata.CurrAsmList,OS_16); cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_16,aint(tcpuabsolutevarsym(symtableentry).addrsegment),location.reference.segment); end; inherited; end; procedure ti8086loadnode.generate_threadvar_access(gvs: tstaticvarsym); var segref: treference; 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 if (cs_compilesystem in current_settings.moduleswitches) then begin inherited generate_threadvar_access(gvs); 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_16,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 else inherited generate_threadvar_access(gvs); end; procedure ti8086loadnode.pass_generate_code; var gvs: tstaticvarsym; segref: treference; refsym: TAsmSymbol; segreg: TRegister; newsize: TCgSize; begin if current_settings.x86memorymodel=mm_huge then begin case symtableentry.typ of staticvarsym: begin gvs:=tstaticvarsym(symtableentry); if (vo_is_dll_var in gvs.varoptions) then { DLL variable } begin inherited pass_generate_code; exit; end { Thread variable } else if (vo_is_thread_var in gvs.varoptions) then begin { this will be handled in ti8086loadnode.generate_threadvar_access } inherited pass_generate_code; exit; end { Normal (or external) variable } else begin if not (vo_is_external in gvs.varoptions) and gvs.Owner.iscurrentunit 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); if gvs.localloc.loc=LOC_INVALID then begin if not(vo_is_weak_external in gvs.varoptions) then refsym:=current_asmdata.RefAsmSymbol(gvs.mangledname) else refsym:=current_asmdata.WeakRefAsmSymbol(gvs.mangledname); segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16); reference_reset_symbol(segref,refsym,0,0); segref.refaddr:=addr_seg; cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg); reference_reset_symbol(location.reference,refsym,0,location.reference.alignment); location.reference.segment:=segreg; end else location:=gvs.localloc; end; { make const a LOC_CREFERENCE } if (gvs.varspez=vs_const) and (location.loc=LOC_REFERENCE) then location.loc:=LOC_CREFERENCE; end; else inherited pass_generate_code; end; end else inherited pass_generate_code; end; begin cloadnode:=ti8086loadnode; end.