n8086ld.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. procedure generate_threadvar_access(gvs: tstaticvarsym); override;
  31. public
  32. procedure pass_generate_code;override;
  33. end;
  34. implementation
  35. uses
  36. globals,verbose,aasmdata,defutil,
  37. symconst,symdef,symtable,symcpu,
  38. nld,
  39. cgbase,cgobj,cgutils,
  40. hlcgobj,
  41. cpubase,cpuinfo,
  42. parabase,paramgr;
  43. {*****************************************************************************
  44. TI8086LOADNODE
  45. *****************************************************************************}
  46. procedure ti8086loadnode.generate_nested_access(vs: tsym);
  47. begin
  48. inherited;
  49. { the parentfp pointer is always a near pointer (this is turbo pascal
  50. compatible) regardless of memory model, so we need to set the segment
  51. manually.
  52. todo: once the far data memory models are fully implemented, the
  53. parentfp type should be changed to a near 'ss' pointer in all memory
  54. models and then this code can be removed. But this can only happen
  55. after:
  56. 1) all calls to a_loadaddr_ref_reg go through the high level code
  57. generator
  58. 2) a_loadaddr_ref_reg in the low level code generator stops using
  59. the presence of a segment in the source reference to determine the
  60. destination reg size
  61. 3) make_simple_ref is updated to remove unnecessary segment prefixes
  62. 4) hlcg.reference_reset_base is updated to set the segment on near_ss
  63. pointers }
  64. if (left.nodetype=loadparentfpn) and
  65. (current_settings.x86memorymodel in x86_far_data_models) then
  66. location.reference.segment:=NR_SS;
  67. end;
  68. procedure ti8086loadnode.generate_absaddr_access(vs: tabsolutevarsym);
  69. begin
  70. if tcpuabsolutevarsym(symtableentry).absseg then
  71. begin
  72. location.reference.segment:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  73. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_16,aint(tcpuabsolutevarsym(symtableentry).addrsegment),location.reference.segment);
  74. end;
  75. inherited;
  76. end;
  77. procedure ti8086loadnode.generate_threadvar_access(gvs: tstaticvarsym);
  78. var
  79. segref: treference;
  80. segreg: TRegister;
  81. newsize: TCgSize;
  82. norelocatelab: TAsmLabel;
  83. endrelocatelab: TAsmLabel;
  84. pvd: tdef;
  85. paraloc1 : tcgpara;
  86. hregister: TRegister;
  87. href: treference;
  88. begin
  89. if current_settings.x86memorymodel=mm_huge then
  90. begin
  91. if (cs_compilesystem in current_settings.moduleswitches) then
  92. begin
  93. inherited generate_threadvar_access(gvs);
  94. exit;
  95. end;
  96. { we don't know the size of all arrays }
  97. newsize:=def_cgsize(resultdef);
  98. { alignment is overridden per case below }
  99. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment,[]);
  100. {
  101. Thread var loading is optimized to first check if
  102. a relocate function is available. When the function
  103. is available it is called to retrieve the address.
  104. Otherwise the address is loaded with the symbol
  105. The code needs to be in the order to first handle the
  106. call and then the address load to be sure that the
  107. register that is used for returning is the same (PFV)
  108. }
  109. current_asmdata.getjumplabel(norelocatelab);
  110. current_asmdata.getjumplabel(endrelocatelab);
  111. { make sure hregister can't allocate the register necessary for the parameter }
  112. pvd:=search_system_type('TRELOCATETHREADVARHANDLER').typedef;
  113. if pvd.typ<>procvardef then
  114. internalerror(2012120901);
  115. paraloc1.init;
  116. paramanager.getintparaloc(current_asmdata.CurrAsmList,tprocvardef(pvd),1,paraloc1);
  117. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pvd);
  118. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  119. reference_reset_symbol(segref,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE',AT_DATA),0,pvd.alignment,[]);
  120. segref.refaddr:=addr_seg;
  121. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  122. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE',AT_DATA),0,pvd.alignment,[]);
  123. href.segment:=segreg;
  124. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,pvd,pvd,href,hregister);
  125. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,pvd,OC_EQ,0,hregister,norelocatelab);
  126. { don't save the allocated register else the result will be destroyed later }
  127. if not(vo_is_weak_external in gvs.varoptions) then
  128. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA),0,2,[])
  129. else
  130. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA),0,2,[]);
  131. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_16,href,paraloc1);
  132. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  133. paraloc1.done;
  134. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  135. cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
  136. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  137. cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  138. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  139. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
  140. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
  141. cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
  142. cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
  143. { no relocation needed, load the address of the variable only, the
  144. layout of a threadvar is (4 bytes pointer):
  145. 0 - Threadvar index
  146. 4 - Threadvar value in single threading }
  147. if not(vo_is_weak_external in gvs.varoptions) then
  148. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA),sizeof(pint),2,[])
  149. else
  150. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA),sizeof(pint),2,[]);
  151. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,voidpointertype,href,hregister);
  152. cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
  153. hlcg.reference_reset_base(location.reference,voidpointertype,hregister,0,location.reference.alignment,[]);
  154. end
  155. else
  156. inherited generate_threadvar_access(gvs);
  157. end;
  158. procedure ti8086loadnode.pass_generate_code;
  159. var
  160. gvs: tstaticvarsym;
  161. segref: treference;
  162. refsym: TAsmSymbol;
  163. segreg: TRegister;
  164. newsize: TCgSize;
  165. begin
  166. if current_settings.x86memorymodel=mm_huge then
  167. begin
  168. case symtableentry.typ of
  169. staticvarsym:
  170. begin
  171. gvs:=tstaticvarsym(symtableentry);
  172. if (vo_is_dll_var in gvs.varoptions) then
  173. { DLL variable }
  174. begin
  175. inherited pass_generate_code;
  176. exit;
  177. end
  178. { Thread variable }
  179. else if (vo_is_thread_var in gvs.varoptions) then
  180. begin
  181. { this will be handled in ti8086loadnode.generate_threadvar_access }
  182. inherited pass_generate_code;
  183. exit;
  184. end
  185. { Normal (or external) variable }
  186. else
  187. begin
  188. if not (vo_is_external in gvs.varoptions) and gvs.Owner.iscurrentunit then
  189. begin
  190. inherited pass_generate_code;
  191. exit;
  192. end;
  193. { we don't know the size of all arrays }
  194. newsize:=def_cgsize(resultdef);
  195. { alignment is overridden per case below }
  196. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment,[]);
  197. if gvs.localloc.loc=LOC_INVALID then
  198. begin
  199. if not(vo_is_weak_external in gvs.varoptions) then
  200. refsym:=current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA)
  201. else
  202. refsym:=current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA);
  203. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  204. reference_reset_symbol(segref,refsym,0,0,[]);
  205. segref.refaddr:=addr_seg;
  206. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  207. reference_reset_symbol(location.reference,refsym,0,location.reference.alignment,[]);
  208. location.reference.segment:=segreg;
  209. end
  210. else
  211. location:=gvs.localloc;
  212. end;
  213. { make const a LOC_CREFERENCE }
  214. if (gvs.varspez=vs_const) and
  215. (location.loc=LOC_REFERENCE) then
  216. location.loc:=LOC_CREFERENCE;
  217. end;
  218. else
  219. inherited pass_generate_code;
  220. end;
  221. end
  222. else
  223. inherited pass_generate_code;
  224. end;
  225. begin
  226. cloadnode:=ti8086loadnode;
  227. end.