n8086ld.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. {
  2. Copyright (c) 2002-2014 by Florian Klaempfl
  3. Generate i8086 assembler for load nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit n8086ld;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. symsym,symtype,
  23. node,ncgld,nx86ld,aasmbase;
  24. type
  25. { ti8086loadnode }
  26. ti8086loadnode = class(tx86loadnode)
  27. protected
  28. procedure generate_nested_access(vs: tsym); override;
  29. procedure generate_absaddr_access(vs: tabsolutevarsym); override;
  30. public
  31. procedure pass_generate_code;override;
  32. end;
  33. implementation
  34. uses
  35. globals,verbose,aasmdata,defutil,
  36. symconst,symdef,symtable,symcpu,
  37. nld,
  38. cgbase,cgobj,cgutils,
  39. hlcgobj,
  40. cpubase,cpuinfo,
  41. parabase,paramgr;
  42. {*****************************************************************************
  43. TI8086LOADNODE
  44. *****************************************************************************}
  45. procedure ti8086loadnode.generate_nested_access(vs: tsym);
  46. begin
  47. inherited;
  48. { the parentfp pointer is always a near pointer (this is turbo pascal
  49. compatible) regardless of memory model, so we need to set the segment
  50. manually.
  51. todo: once the far data memory models are fully implemented, the
  52. parentfp type should be changed to a near 'ss' pointer in all memory
  53. models and then this code can be removed. But this can only happen
  54. after:
  55. 1) all calls to a_loadaddr_ref_reg go through the high level code
  56. generator
  57. 2) a_loadaddr_ref_reg in the low level code generator stops using
  58. the presence of a segment in the source reference to determine the
  59. destination reg size
  60. 3) make_simple_ref is updated to remove unnecessary segment prefixes
  61. 4) hlcg.reference_reset_base is updated to set the segment on near_ss
  62. pointers }
  63. if (left.nodetype=loadparentfpn) and
  64. (current_settings.x86memorymodel in x86_far_data_models) then
  65. location.reference.segment:=NR_SS;
  66. end;
  67. procedure ti8086loadnode.generate_absaddr_access(vs: tabsolutevarsym);
  68. begin
  69. if tcpuabsolutevarsym(symtableentry).absseg then
  70. begin
  71. location.reference.segment:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  72. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_16,aint(tcpuabsolutevarsym(symtableentry).addrsegment),location.reference.segment);
  73. end;
  74. inherited;
  75. end;
  76. procedure ti8086loadnode.pass_generate_code;
  77. var
  78. gvs: tstaticvarsym;
  79. segref: treference;
  80. refsym: TAsmSymbol;
  81. segreg: TRegister;
  82. newsize: TCgSize;
  83. norelocatelab: TAsmLabel;
  84. endrelocatelab: TAsmLabel;
  85. pvd: tdef;
  86. paraloc1 : tcgpara;
  87. hregister: TRegister;
  88. href: treference;
  89. begin
  90. if current_settings.x86memorymodel=mm_huge then
  91. begin
  92. case symtableentry.typ of
  93. staticvarsym:
  94. begin
  95. gvs:=tstaticvarsym(symtableentry);
  96. if (vo_is_dll_var in gvs.varoptions) then
  97. { DLL variable }
  98. begin
  99. inherited pass_generate_code;
  100. exit;
  101. end
  102. { Thread variable }
  103. else if (vo_is_thread_var in gvs.varoptions) then
  104. begin
  105. if (cs_compilesystem in current_settings.moduleswitches) then
  106. begin
  107. inherited pass_generate_code;
  108. exit;
  109. end;
  110. { we don't know the size of all arrays }
  111. newsize:=def_cgsize(resultdef);
  112. { alignment is overridden per case below }
  113. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment);
  114. {
  115. Thread var loading is optimized to first check if
  116. a relocate function is available. When the function
  117. is available it is called to retrieve the address.
  118. Otherwise the address is loaded with the symbol
  119. The code needs to be in the order to first handle the
  120. call and then the address load to be sure that the
  121. register that is used for returning is the same (PFV)
  122. }
  123. current_asmdata.getjumplabel(norelocatelab);
  124. current_asmdata.getjumplabel(endrelocatelab);
  125. { make sure hregister can't allocate the register necessary for the parameter }
  126. pvd:=search_system_type('TRELOCATETHREADVARHANDLER').typedef;
  127. if pvd.typ<>procvardef then
  128. internalerror(2012120901);
  129. paraloc1.init;
  130. paramanager.getintparaloc(current_asmdata.CurrAsmList,tprocvardef(pvd),1,paraloc1);
  131. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pvd);
  132. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  133. reference_reset_symbol(segref,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0,0);
  134. segref.refaddr:=addr_seg;
  135. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  136. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0,pvd.size);
  137. href.segment:=segreg;
  138. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,pvd,pvd,href,hregister);
  139. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,pvd,OC_EQ,0,hregister,norelocatelab);
  140. { don't save the allocated register else the result will be destroyed later }
  141. if not(vo_is_weak_external in gvs.varoptions) then
  142. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname),0,sizeof(pint))
  143. else
  144. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),0,sizeof(pint));
  145. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  146. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  147. paraloc1.done;
  148. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  149. cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
  150. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  151. cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  152. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  153. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
  154. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
  155. cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
  156. cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
  157. { no relocation needed, load the address of the variable only, the
  158. layout of a threadvar is (4 bytes pointer):
  159. 0 - Threadvar index
  160. 4 - Threadvar value in single threading }
  161. if not(vo_is_weak_external in gvs.varoptions) then
  162. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname),sizeof(pint),sizeof(pint))
  163. else
  164. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),sizeof(pint),sizeof(pint));
  165. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,voidpointertype,href,hregister);
  166. cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
  167. hlcg.reference_reset_base(location.reference,voidpointertype,hregister,0,location.reference.alignment);
  168. end
  169. { Normal (or external) variable }
  170. else
  171. begin
  172. if not (vo_is_external in gvs.varoptions) and gvs.Owner.iscurrentunit then
  173. begin
  174. inherited pass_generate_code;
  175. exit;
  176. end;
  177. { we don't know the size of all arrays }
  178. newsize:=def_cgsize(resultdef);
  179. { alignment is overridden per case below }
  180. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment);
  181. if gvs.localloc.loc=LOC_INVALID then
  182. begin
  183. if not(vo_is_weak_external in gvs.varoptions) then
  184. refsym:=current_asmdata.RefAsmSymbol(gvs.mangledname)
  185. else
  186. refsym:=current_asmdata.WeakRefAsmSymbol(gvs.mangledname);
  187. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  188. reference_reset_symbol(segref,refsym,0,0);
  189. segref.refaddr:=addr_seg;
  190. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  191. reference_reset_symbol(location.reference,refsym,0,location.reference.alignment);
  192. location.reference.segment:=segreg;
  193. end
  194. else
  195. location:=gvs.localloc;
  196. end;
  197. { make const a LOC_CREFERENCE }
  198. if (gvs.varspez=vs_const) and
  199. (location.loc=LOC_REFERENCE) then
  200. location.loc:=LOC_CREFERENCE;
  201. end;
  202. else
  203. inherited pass_generate_code;
  204. end;
  205. end
  206. else
  207. inherited pass_generate_code;
  208. end;
  209. begin
  210. cloadnode:=ti8086loadnode;
  211. end.