cgcpu.pas 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the i8086
  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 cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cgbase,cgobj,cg64f32,cgx86,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. cpubase,parabase,cgutils,
  25. symconst,symdef
  26. ;
  27. type
  28. { tcg8086 }
  29. tcg8086 = class(tcgx86)
  30. procedure init_register_allocators;override;
  31. procedure do_register_allocation(list:TAsmList;headertai:tai);override;
  32. function getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
  33. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  34. procedure a_call_name_far(list : TAsmList;const s : string; weak: boolean);
  35. procedure a_call_name_static(list : TAsmList;const s : string);override;
  36. procedure a_call_name_static_far(list : TAsmList;const s : string);
  37. procedure a_call_reg(list : TAsmList;reg : tregister);override;
  38. procedure a_call_reg_far(list : TAsmList;reg : tregister);
  39. procedure a_call_ref(list : TAsmList;ref : treference);override;
  40. procedure a_call_ref_far(list : TAsmList;ref : treference);
  41. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  42. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  43. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  44. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  45. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  46. procedure push_const(list:TAsmList;size:tcgsize;a:tcgint);
  47. { passing parameter using push instead of mov }
  48. procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  49. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
  50. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  51. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
  52. { move instructions }
  53. procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
  54. procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
  55. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  56. procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  57. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  58. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);override;
  59. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);override;
  60. procedure g_stackpointer_alloc(list : TAsmList;localsize: longint);override;
  61. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  62. procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  63. procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  64. procedure g_exception_reason_save(list : TAsmList; const href : treference);override;
  65. procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: tcgint);override;
  66. procedure g_exception_reason_load(list : TAsmList; const href : treference);override;
  67. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);override;
  68. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  69. procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
  70. procedure add_move_instruction(instr:Taicpu);override;
  71. end;
  72. tcg64f8086 = class(tcg64f32)
  73. procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
  74. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  75. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  76. procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
  77. private
  78. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  79. end;
  80. procedure create_codegen;
  81. implementation
  82. uses
  83. globals,verbose,systems,cutils,
  84. paramgr,procinfo,fmodule,
  85. rgcpu,rgx86,cpuinfo,
  86. symtype,symsym,
  87. tgobj;
  88. function use_push(const cgpara:tcgpara):boolean;
  89. begin
  90. result:=(not paramanager.use_fixed_stack) and
  91. assigned(cgpara.location) and
  92. (cgpara.location^.loc=LOC_REFERENCE) and
  93. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  94. end;
  95. procedure tcg8086.init_register_allocators;
  96. begin
  97. inherited init_register_allocators;
  98. if not(target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  99. (cs_create_pic in current_settings.moduleswitches) then
  100. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI],first_int_imreg,[RS_BP])
  101. else
  102. if (cs_useebp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer<>NR_BP) then
  103. 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,[])
  104. else
  105. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI],first_int_imreg,[RS_BP]);
  106. 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,[]);
  107. 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,[]);
  108. rgfpu:=Trgx86fpu.create;
  109. end;
  110. procedure tcg8086.do_register_allocation(list:TAsmList;headertai:tai);
  111. begin
  112. if (pi_needs_got in current_procinfo.flags) then
  113. begin
  114. if getsupreg(current_procinfo.got) < first_int_imreg then
  115. include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
  116. end;
  117. inherited do_register_allocation(list,headertai);
  118. end;
  119. function tcg8086.getintregister(list: TAsmList; size: Tcgsize): Tregister;
  120. begin
  121. case size of
  122. OS_8, OS_S8,
  123. OS_16, OS_S16:
  124. Result := inherited getintregister(list, size);
  125. OS_32, OS_S32:
  126. begin
  127. Result:=inherited getintregister(list, OS_16);
  128. { ensure that the high register can be retrieved by
  129. GetNextReg
  130. }
  131. if inherited getintregister(list, OS_16)<>GetNextReg(Result) then
  132. internalerror(2013030202);
  133. end;
  134. else
  135. internalerror(2013030201);
  136. end;
  137. end;
  138. procedure tcg8086.a_call_name(list: TAsmList; const s: string; weak: boolean);
  139. begin
  140. if current_settings.x86memorymodel in x86_far_code_models then
  141. a_call_name_far(list,s,weak)
  142. else
  143. a_call_name_near(list,s,weak);
  144. end;
  145. procedure tcg8086.a_call_name_far(list: TAsmList; const s: string;
  146. weak: boolean);
  147. var
  148. sym : tasmsymbol;
  149. r : treference;
  150. begin
  151. if not(weak) then
  152. sym:=current_asmdata.RefAsmSymbol(s)
  153. else
  154. sym:=current_asmdata.WeakRefAsmSymbol(s);
  155. reference_reset_symbol(r,sym,0,sizeof(pint));
  156. r.refaddr:=addr_far;
  157. list.concat(taicpu.op_ref(A_CALL,S_NO,r));
  158. end;
  159. procedure tcg8086.a_call_name_static(list: TAsmList; const s: string);
  160. begin
  161. if current_settings.x86memorymodel in x86_far_code_models then
  162. a_call_name_static_far(list,s)
  163. else
  164. a_call_name_static_near(list,s);
  165. end;
  166. procedure tcg8086.a_call_name_static_far(list: TAsmList; const s: string);
  167. var
  168. sym : tasmsymbol;
  169. r : treference;
  170. begin
  171. sym:=current_asmdata.RefAsmSymbol(s);
  172. reference_reset_symbol(r,sym,0,sizeof(pint));
  173. r.refaddr:=addr_far;
  174. list.concat(taicpu.op_ref(A_CALL,S_NO,r));
  175. end;
  176. procedure tcg8086.a_call_reg(list: TAsmList; reg: tregister);
  177. begin
  178. if current_settings.x86memorymodel in x86_far_code_models then
  179. a_call_reg_far(list,reg)
  180. else
  181. a_call_reg_near(list,reg);
  182. end;
  183. procedure tcg8086.a_call_reg_far(list: TAsmList; reg: tregister);
  184. var
  185. href: treference;
  186. begin
  187. { unfortunately, x86 doesn't have a 'call far reg:reg' instruction, so }
  188. { we have to use a temp }
  189. tg.gettemp(list,4,2,tt_normal,href);
  190. { HACK!!! at this point all registers are allocated, due to the fact that
  191. in the pascal calling convention, all registers are caller saved. This
  192. causes the register allocator to fail on the next move instruction, so we
  193. temporarily deallocate 2 registers.
  194. TODO: figure out a better way to do this. }
  195. cg.ungetcpuregister(list,NR_BX);
  196. cg.ungetcpuregister(list,NR_SI);
  197. a_load_reg_ref(list,OS_32,OS_32,reg,href);
  198. cg.getcpuregister(list,NR_BX);
  199. cg.getcpuregister(list,NR_SI);
  200. a_call_ref_far(list,href);
  201. tg.ungettemp(list,href);
  202. end;
  203. procedure tcg8086.a_call_ref(list: TAsmList; ref: treference);
  204. begin
  205. if current_settings.x86memorymodel in x86_far_code_models then
  206. a_call_ref_far(list,ref)
  207. else
  208. a_call_ref_near(list,ref);
  209. end;
  210. procedure tcg8086.a_call_ref_far(list: TAsmList; ref: treference);
  211. begin
  212. ref.refaddr:=addr_far_ref;
  213. list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
  214. end;
  215. procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  216. a: tcgint; reg: TRegister);
  217. var
  218. tmpreg: tregister;
  219. op1, op2: TAsmOp;
  220. ax_subreg: tregister;
  221. hl_loop_start: tasmlabel;
  222. ai: taicpu;
  223. use_loop: Boolean;
  224. i: Integer;
  225. begin
  226. optimize_op_const(op, a);
  227. check_register_size(size,reg);
  228. if size in [OS_64, OS_S64] then
  229. internalerror(2013030904);
  230. if size in [OS_32, OS_S32] then
  231. begin
  232. case op of
  233. OP_NONE:
  234. begin
  235. { Opcode is optimized away }
  236. end;
  237. OP_MOVE:
  238. begin
  239. { Optimized, replaced with a simple load }
  240. a_load_const_reg(list,size,a,reg);
  241. end;
  242. OP_ADD, OP_SUB:
  243. begin
  244. get_32bit_ops(op, op1, op2);
  245. { Optimization when the low 16-bits of the constant are 0 }
  246. if aint(a and $FFFF) = 0 then
  247. begin
  248. list.concat(taicpu.op_const_reg(op1,S_W,aint(a shr 16),GetNextReg(reg)));
  249. end
  250. else
  251. begin
  252. list.concat(taicpu.op_const_reg(op1,S_W,aint(a and $FFFF),reg));
  253. list.concat(taicpu.op_const_reg(op2,S_W,aint(a shr 16),GetNextReg(reg)));
  254. end;
  255. end;
  256. OP_AND, OP_OR, OP_XOR:
  257. begin
  258. if longword(a) = high(longword) then
  259. begin
  260. case op of
  261. OP_AND:
  262. exit;
  263. OP_OR:
  264. a_load_const_reg(list,size,high(longword),reg);
  265. OP_XOR:
  266. begin
  267. list.concat(taicpu.op_reg(A_NOT,S_W,reg));
  268. list.concat(taicpu.op_reg(A_NOT,S_W,GetNextReg(reg)));
  269. end;
  270. else
  271. InternalError(2013100701);
  272. end
  273. end
  274. else
  275. begin
  276. a_op_const_reg(list,op,OS_16,aint(a and $FFFF),reg);
  277. a_op_const_reg(list,op,OS_16,aint(a shr 16),GetNextReg(reg));
  278. end;
  279. end;
  280. OP_SHR,OP_SHL,OP_SAR:
  281. begin
  282. a:=a and 31;
  283. { for shl with const >= 16, we can just move the low register
  284. to the high reg, then zero the low register, then do the
  285. remaining part of the shift (by const-16) in 16 bit on the
  286. high register. the same thing applies to shr with low and high
  287. reversed. sar is exactly like shr, except that instead of
  288. zeroing the high register, we sar it by 15. }
  289. if a>=16 then
  290. case op of
  291. OP_SHR:
  292. begin
  293. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  294. a_load_const_reg(list,OS_16,0,GetNextReg(reg));
  295. a_op_const_reg(list,OP_SHR,OS_16,a-16,reg);
  296. end;
  297. OP_SHL:
  298. begin
  299. a_load_reg_reg(list,OS_16,OS_16,reg,GetNextReg(reg));
  300. a_load_const_reg(list,OS_16,0,reg);
  301. a_op_const_reg(list,OP_SHL,OS_16,a-16,GetNextReg(reg));
  302. end;
  303. OP_SAR:
  304. begin
  305. if a=31 then
  306. begin
  307. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  308. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  309. end
  310. else
  311. begin
  312. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  313. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  314. a_op_const_reg(list,OP_SAR,OS_16,a-16,reg);
  315. end;
  316. end;
  317. else
  318. internalerror(2013060201);
  319. end
  320. else if a<>0 then
  321. begin
  322. use_loop:=a>2;
  323. if use_loop then
  324. begin
  325. getcpuregister(list,NR_CX);
  326. a_load_const_reg(list,OS_16,a,NR_CX);
  327. current_asmdata.getjumplabel(hl_loop_start);
  328. a_label(list,hl_loop_start);
  329. case op of
  330. OP_SHR:
  331. begin
  332. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  333. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  334. end;
  335. OP_SAR:
  336. begin
  337. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  338. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  339. end;
  340. OP_SHL:
  341. begin
  342. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  343. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  344. end;
  345. else
  346. internalerror(2013030903);
  347. end;
  348. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  349. ai.is_jmp:=true;
  350. list.concat(ai);
  351. ungetcpuregister(list,NR_CX);
  352. end
  353. else
  354. begin
  355. for i:=1 to a do
  356. begin
  357. case op of
  358. OP_SHR:
  359. begin
  360. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  361. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  362. end;
  363. OP_SAR:
  364. begin
  365. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  366. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  367. end;
  368. OP_SHL:
  369. begin
  370. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  371. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  372. end;
  373. else
  374. internalerror(2013030903);
  375. end;
  376. end;
  377. end;
  378. end;
  379. end;
  380. else
  381. begin
  382. tmpreg:=getintregister(list,size);
  383. a_load_const_reg(list,size,a,tmpreg);
  384. a_op_reg_reg(list,op,size,tmpreg,reg);
  385. end;
  386. end;
  387. end
  388. else
  389. begin
  390. { size <= 16-bit }
  391. { 8086 doesn't support 'imul reg,const', so we handle it here }
  392. if (current_settings.cputype<cpu_186) and (op in [OP_MUL,OP_IMUL]) then
  393. begin
  394. { TODO: also enable the SHL optimization below }
  395. { if not(cs_check_overflow in current_settings.localswitches) and
  396. ispowerof2(int64(a),power) then
  397. begin
  398. list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
  399. exit;
  400. end;}
  401. if op = OP_IMUL then
  402. begin
  403. if size in [OS_16,OS_S16] then
  404. ax_subreg := NR_AX
  405. else
  406. if size in [OS_8,OS_S8] then
  407. ax_subreg := NR_AL
  408. else
  409. internalerror(2013050102);
  410. getcpuregister(list,NR_AX);
  411. a_load_const_reg(list,size,a,ax_subreg);
  412. if size in [OS_16,OS_S16] then
  413. getcpuregister(list,NR_DX);
  414. list.concat(taicpu.op_reg(A_IMUL,TCgSize2OpSize[size],reg));
  415. if size in [OS_16,OS_S16] then
  416. ungetcpuregister(list,NR_DX);
  417. a_load_reg_reg(list,size,size,ax_subreg,reg);
  418. ungetcpuregister(list,NR_AX);
  419. { TODO: implement overflow checking? }
  420. exit;
  421. end
  422. else
  423. { OP_MUL should be handled specifically in the code }
  424. { generator because of the silly register usage restraints }
  425. internalerror(200109225);
  426. end
  427. else
  428. inherited a_op_const_reg(list, Op, size, a, reg);
  429. end;
  430. end;
  431. procedure tcg8086.a_op_const_ref(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  432. var
  433. tmpref: treference;
  434. op1,op2: TAsmOp;
  435. begin
  436. optimize_op_const(op, a);
  437. tmpref:=ref;
  438. make_simple_ref(list,tmpref);
  439. if size in [OS_64, OS_S64] then
  440. internalerror(2013050801);
  441. if size in [OS_32, OS_S32] then
  442. begin
  443. case Op of
  444. OP_NONE :
  445. begin
  446. { Opcode is optimized away }
  447. end;
  448. OP_MOVE :
  449. begin
  450. { Optimized, replaced with a simple load }
  451. a_load_const_ref(list,size,a,ref);
  452. end;
  453. OP_ADD, OP_SUB:
  454. begin
  455. get_32bit_ops(op, op1, op2);
  456. { Optimization when the low 16-bits of the constant are 0 }
  457. if aint(a and $FFFF) = 0 then
  458. begin
  459. inc(tmpref.offset, 2);
  460. list.concat(taicpu.op_const_ref(op1,S_W,aint(a shr 16),tmpref));
  461. end
  462. else
  463. begin
  464. list.concat(taicpu.op_const_ref(op1,S_W,aint(a and $FFFF),tmpref));
  465. inc(tmpref.offset, 2);
  466. list.concat(taicpu.op_const_ref(op2,S_W,aint(a shr 16),tmpref));
  467. end;
  468. end;
  469. OP_AND, OP_OR, OP_XOR:
  470. begin
  471. if longword(a) = high(longword) then
  472. begin
  473. case op of
  474. OP_AND:
  475. exit;
  476. OP_OR:
  477. a_load_const_ref(list,size,high(longword),tmpref);
  478. OP_XOR:
  479. begin
  480. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  481. inc(tmpref.offset, 2);
  482. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  483. end;
  484. else
  485. InternalError(2013100701);
  486. end
  487. end
  488. else
  489. begin
  490. a_op_const_ref(list,op,OS_16,aint(a and $FFFF),tmpref);
  491. inc(tmpref.offset, 2);
  492. a_op_const_ref(list,op,OS_16,aint(a shr 16),tmpref);
  493. end;
  494. end;
  495. else
  496. internalerror(2013050802);
  497. end;
  498. end
  499. else
  500. inherited a_op_const_ref(list,Op,size,a,tmpref);
  501. end;
  502. procedure tcg8086.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  503. src, dst: TRegister);
  504. var
  505. op1, op2: TAsmOp;
  506. hl_skip, hl_loop_start: TAsmLabel;
  507. ai: taicpu;
  508. begin
  509. check_register_size(size,src);
  510. check_register_size(size,dst);
  511. if size in [OS_64, OS_S64] then
  512. internalerror(2013030902);
  513. if size in [OS_32, OS_S32] then
  514. begin
  515. case op of
  516. OP_NEG:
  517. begin
  518. if src<>dst then
  519. a_load_reg_reg(list,size,size,src,dst);
  520. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  521. list.concat(taicpu.op_reg(A_NEG, S_W, dst));
  522. list.concat(taicpu.op_const_reg(A_SBB, S_W,-1, GetNextReg(dst)));
  523. end;
  524. OP_NOT:
  525. begin
  526. if src<>dst then
  527. a_load_reg_reg(list,size,size,src,dst);
  528. list.concat(taicpu.op_reg(A_NOT, S_W, dst));
  529. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  530. end;
  531. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  532. begin
  533. get_32bit_ops(op, op1, op2);
  534. list.concat(taicpu.op_reg_reg(op1, S_W, src, dst));
  535. list.concat(taicpu.op_reg_reg(op2, S_W, GetNextReg(src), GetNextReg(dst)));
  536. end;
  537. OP_SHR,OP_SHL,OP_SAR:
  538. begin
  539. getcpuregister(list,NR_CX);
  540. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  541. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  542. current_asmdata.getjumplabel(hl_skip);
  543. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  544. ai.SetCondition(C_Z);
  545. ai.is_jmp:=true;
  546. list.concat(ai);
  547. current_asmdata.getjumplabel(hl_loop_start);
  548. a_label(list,hl_loop_start);
  549. case op of
  550. OP_SHR:
  551. begin
  552. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(dst)));
  553. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  554. end;
  555. OP_SAR:
  556. begin
  557. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(dst)));
  558. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  559. end;
  560. OP_SHL:
  561. begin
  562. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,dst));
  563. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(dst)));
  564. end;
  565. else
  566. internalerror(2013030903);
  567. end;
  568. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  569. ai.is_jmp:=true;
  570. list.concat(ai);
  571. a_label(list,hl_skip);
  572. ungetcpuregister(list,NR_CX);
  573. end;
  574. else
  575. internalerror(2013030901);
  576. end;
  577. end
  578. else
  579. inherited a_op_reg_reg(list, Op, size, src, dst);
  580. end;
  581. procedure tcg8086.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  582. var
  583. tmpref : treference;
  584. op1, op2: TAsmOp;
  585. begin
  586. tmpref:=ref;
  587. make_simple_ref(list,tmpref);
  588. check_register_size(size,reg);
  589. if size in [OS_64, OS_S64] then
  590. internalerror(2013030902);
  591. if size in [OS_32, OS_S32] then
  592. begin
  593. case op of
  594. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  595. begin
  596. get_32bit_ops(op, op1, op2);
  597. list.concat(taicpu.op_ref_reg(op1, S_W, tmpref, reg));
  598. inc(tmpref.offset, 2);
  599. list.concat(taicpu.op_ref_reg(op2, S_W, tmpref, GetNextReg(reg)));
  600. end;
  601. else
  602. internalerror(2013050701);
  603. end;
  604. end
  605. else
  606. inherited a_op_ref_reg(list,Op,size,tmpref,reg);
  607. end;
  608. procedure tcg8086.a_op_reg_ref(list: TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference);
  609. var
  610. tmpref: treference;
  611. op1,op2: TAsmOp;
  612. begin
  613. tmpref:=ref;
  614. make_simple_ref(list,tmpref);
  615. check_register_size(size,reg);
  616. if size in [OS_64, OS_S64] then
  617. internalerror(2013050803);
  618. if size in [OS_32, OS_S32] then
  619. begin
  620. case op of
  621. OP_NEG:
  622. begin
  623. if reg<>NR_NO then
  624. internalerror(200109237);
  625. inc(tmpref.offset, 2);
  626. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  627. dec(tmpref.offset, 2);
  628. list.concat(taicpu.op_ref(A_NEG, S_W, tmpref));
  629. inc(tmpref.offset, 2);
  630. list.concat(taicpu.op_const_ref(A_SBB, S_W,-1, tmpref));
  631. end;
  632. OP_NOT:
  633. begin
  634. if reg<>NR_NO then
  635. internalerror(200109237);
  636. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  637. inc(tmpref.offset, 2);
  638. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  639. end;
  640. OP_IMUL:
  641. begin
  642. { this one needs a load/imul/store, which is the default }
  643. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  644. end;
  645. OP_MUL,OP_DIV,OP_IDIV:
  646. { special stuff, needs separate handling inside code }
  647. { generator }
  648. internalerror(200109238);
  649. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  650. begin
  651. get_32bit_ops(op, op1, op2);
  652. list.concat(taicpu.op_reg_ref(op1, S_W, reg, tmpref));
  653. inc(tmpref.offset, 2);
  654. list.concat(taicpu.op_reg_ref(op2, S_W, GetNextReg(reg), tmpref));
  655. end;
  656. else
  657. internalerror(2013050804);
  658. end;
  659. end
  660. else
  661. inherited a_op_reg_ref(list,Op,size,reg,tmpref);
  662. end;
  663. procedure tcg8086.push_const(list: TAsmList; size: tcgsize; a: tcgint);
  664. var
  665. tmpreg: TRegister;
  666. begin
  667. if not (size in [OS_16,OS_S16]) then
  668. internalerror(2013043001);
  669. if current_settings.cputype < cpu_186 then
  670. begin
  671. tmpreg:=getintregister(list,size);
  672. a_load_const_reg(list,size,a,tmpreg);
  673. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  674. end
  675. else
  676. list.concat(taicpu.op_const(A_PUSH,TCGSize2OpSize[size],a));
  677. end;
  678. procedure tcg8086.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  679. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  680. var
  681. ref : treference;
  682. begin
  683. paramanager.allocparaloc(list,paraloc);
  684. case paraloc^.loc of
  685. LOC_REGISTER,LOC_CREGISTER:
  686. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  687. LOC_REFERENCE,LOC_CREFERENCE:
  688. begin
  689. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,2);
  690. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  691. end;
  692. else
  693. internalerror(2002071004);
  694. end;
  695. end;
  696. var
  697. pushsize,pushsize2 : tcgsize;
  698. begin
  699. check_register_size(size,r);
  700. if use_push(cgpara) then
  701. begin
  702. if tcgsize2size[cgpara.Size] > 2 then
  703. begin
  704. if tcgsize2size[cgpara.Size] <> 4 then
  705. internalerror(2013031101);
  706. if cgpara.location^.Next = nil then
  707. begin
  708. if tcgsize2size[cgpara.location^.size] <> 4 then
  709. internalerror(2013031101);
  710. end
  711. else
  712. begin
  713. if tcgsize2size[cgpara.location^.size] <> 2 then
  714. internalerror(2013031101);
  715. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  716. internalerror(2013031101);
  717. if cgpara.location^.Next^.Next <> nil then
  718. internalerror(2013031101);
  719. end;
  720. if tcgsize2size[cgpara.size]>cgpara.alignment then
  721. pushsize:=cgpara.size
  722. else
  723. pushsize:=int_cgsize(cgpara.alignment);
  724. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  725. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  726. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  727. end
  728. else
  729. begin
  730. cgpara.check_simple_location;
  731. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  732. pushsize:=cgpara.location^.size
  733. else
  734. pushsize:=int_cgsize(cgpara.alignment);
  735. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  736. end;
  737. end
  738. else
  739. begin
  740. if tcgsize2size[cgpara.Size]=4 then
  741. begin
  742. if (cgpara.location^.Next=nil) or
  743. (tcgsize2size[cgpara.location^.size]<>2) or
  744. (tcgsize2size[cgpara.location^.Next^.size]<>2) or
  745. (cgpara.location^.Next^.Next<>nil) or
  746. (cgpara.location^.shiftval<>0) then
  747. internalerror(2013031102);
  748. load_para_loc(r,cgpara.Location);
  749. load_para_loc(GetNextReg(r),cgpara.Location^.Next);
  750. end
  751. else
  752. inherited a_load_reg_cgpara(list,size,r,cgpara);
  753. end;
  754. end;
  755. procedure tcg8086.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
  756. var
  757. pushsize : tcgsize;
  758. begin
  759. if use_push(cgpara) then
  760. begin
  761. if tcgsize2size[cgpara.Size] > 2 then
  762. begin
  763. if tcgsize2size[cgpara.Size] <> 4 then
  764. internalerror(2013031101);
  765. if cgpara.location^.Next = nil then
  766. begin
  767. if tcgsize2size[cgpara.location^.size] <> 4 then
  768. internalerror(2013031101);
  769. end
  770. else
  771. begin
  772. if tcgsize2size[cgpara.location^.size] <> 2 then
  773. internalerror(2013031101);
  774. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  775. internalerror(2013031101);
  776. if cgpara.location^.Next^.Next <> nil then
  777. internalerror(2013031101);
  778. end;
  779. if (cgpara.alignment <> 4) and (cgpara.alignment <> 2) then
  780. internalerror(2013031101);
  781. push_const(list,OS_16,a shr 16);
  782. push_const(list,OS_16,a and $FFFF);
  783. end
  784. else
  785. begin
  786. cgpara.check_simple_location;
  787. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  788. pushsize:=cgpara.location^.size
  789. else
  790. pushsize:=int_cgsize(cgpara.alignment);
  791. push_const(list,pushsize,a);
  792. end;
  793. end
  794. else
  795. inherited a_load_const_cgpara(list,size,a,cgpara);
  796. end;
  797. procedure tcg8086.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
  798. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  799. var
  800. pushsize : tcgsize;
  801. opsize : topsize;
  802. tmpreg : tregister;
  803. href,tmpref: treference;
  804. begin
  805. if not assigned(paraloc) then
  806. exit;
  807. if (paraloc^.loc<>LOC_REFERENCE) or
  808. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  809. (tcgsize2size[paraloc^.size]>4) then
  810. internalerror(200501162);
  811. { Pushes are needed in reverse order, add the size of the
  812. current location to the offset where to load from. This
  813. prevents wrong calculations for the last location when
  814. the size is not a power of 2 }
  815. if assigned(paraloc^.next) then
  816. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  817. { Push the data starting at ofs }
  818. href:=r;
  819. inc(href.offset,ofs);
  820. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  821. pushsize:=paraloc^.size
  822. else
  823. pushsize:=int_cgsize(cgpara.alignment);
  824. opsize:=TCgsize2opsize[pushsize];
  825. { for go32v2 we obtain OS_F32,
  826. but pushs is not valid, we need pushl }
  827. if opsize=S_FS then
  828. opsize:=S_W;
  829. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  830. begin
  831. tmpreg:=getintregister(list,pushsize);
  832. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  833. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  834. end
  835. else
  836. begin
  837. make_simple_ref(list,href);
  838. if tcgsize2size[pushsize] > 2 then
  839. begin
  840. tmpref := href;
  841. Inc(tmpref.offset, 2);
  842. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  843. end;
  844. list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  845. end;
  846. end;
  847. var
  848. len : tcgint;
  849. href : treference;
  850. begin
  851. { cgpara.size=OS_NO requires a copy on the stack }
  852. if use_push(cgpara) then
  853. begin
  854. { Record copy? }
  855. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  856. begin
  857. cgpara.check_simple_location;
  858. len:=align(cgpara.intsize,cgpara.alignment);
  859. g_stackpointer_alloc(list,len);
  860. reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
  861. g_concatcopy(list,r,href,len);
  862. end
  863. else
  864. begin
  865. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  866. internalerror(200501161);
  867. { We need to push the data in reverse order,
  868. therefor we use a recursive algorithm }
  869. pushdata(cgpara.location,0);
  870. end
  871. end
  872. else
  873. inherited a_load_ref_cgpara(list,size,r,cgpara);
  874. end;
  875. procedure tcg8086.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
  876. var
  877. tmpreg : tregister;
  878. opsize : topsize;
  879. tmpref : treference;
  880. begin
  881. with r do
  882. begin
  883. if use_push(cgpara) then
  884. begin
  885. cgpara.check_simple_location;
  886. opsize:=tcgsize2opsize[OS_ADDR];
  887. if (segment=NR_NO) and (base=NR_NO) and (index=NR_NO) then
  888. begin
  889. if assigned(symbol) then
  890. begin
  891. if current_settings.cputype < cpu_186 then
  892. begin
  893. tmpreg:=getaddressregister(list);
  894. a_loadaddr_ref_reg(list,r,tmpreg);
  895. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  896. end
  897. else
  898. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset));
  899. end
  900. else
  901. push_const(list,OS_ADDR,offset);
  902. end
  903. else if (segment=NR_NO) and (base=NR_NO) and (index<>NR_NO) and
  904. (offset=0) and (scalefactor=0) and (symbol=nil) then
  905. list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
  906. else if (segment=NR_NO) and (base<>NR_NO) and (index=NR_NO) and
  907. (offset=0) and (symbol=nil) then
  908. list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
  909. else
  910. begin
  911. tmpreg:=getaddressregister(list);
  912. a_loadaddr_ref_reg(list,r,tmpreg);
  913. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  914. end;
  915. end
  916. else
  917. inherited a_loadaddr_ref_cgpara(list,r,cgpara);
  918. end;
  919. end;
  920. procedure tcg8086.a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);
  921. begin
  922. check_register_size(tosize,reg);
  923. if tosize in [OS_S32,OS_32] then
  924. begin
  925. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a and $ffff),reg));
  926. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a shr 16),GetNextReg(reg)));
  927. end
  928. else
  929. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg));
  930. end;
  931. procedure tcg8086.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
  932. var
  933. tmpref : treference;
  934. begin
  935. tmpref:=ref;
  936. make_simple_ref(list,tmpref);
  937. if tosize in [OS_S32,OS_32] then
  938. begin
  939. a_load_const_ref(list,OS_16,longint(a and $ffff),tmpref);
  940. inc(tmpref.offset,2);
  941. a_load_const_ref(list,OS_16,longint(a shr 16),tmpref);
  942. end
  943. else
  944. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
  945. end;
  946. procedure tcg8086.a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);
  947. var
  948. tmpreg : tregister;
  949. tmpref : treference;
  950. begin
  951. tmpref:=ref;
  952. make_simple_ref(list,tmpref);
  953. check_register_size(fromsize,reg);
  954. case tosize of
  955. OS_8,OS_S8:
  956. if fromsize in [OS_8,OS_S8] then
  957. list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
  958. else
  959. internalerror(2013030310);
  960. OS_16,OS_S16:
  961. case fromsize of
  962. OS_8,OS_S8:
  963. begin
  964. tmpreg:=getintregister(list,tosize);
  965. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  966. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  967. end;
  968. OS_16,OS_S16:
  969. begin
  970. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  971. end;
  972. else
  973. internalerror(2013030312);
  974. end;
  975. OS_32,OS_S32:
  976. case fromsize of
  977. OS_8,OS_S8,OS_S16:
  978. begin
  979. tmpreg:=getintregister(list,tosize);
  980. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  981. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  982. end;
  983. OS_16:
  984. begin
  985. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  986. inc(tmpref.offset, 2);
  987. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  988. end;
  989. OS_32,OS_S32:
  990. begin
  991. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  992. inc(tmpref.offset, 2);
  993. list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
  994. end;
  995. else
  996. internalerror(2013030313);
  997. end;
  998. else
  999. internalerror(2013030311);
  1000. end;
  1001. end;
  1002. procedure tcg8086.a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);
  1003. procedure add_mov(instr: Taicpu);
  1004. begin
  1005. { Notify the register allocator that we have written a move instruction so
  1006. it can try to eliminate it. }
  1007. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1008. add_move_instruction(instr);
  1009. list.concat(instr);
  1010. end;
  1011. var
  1012. tmpref : treference;
  1013. begin
  1014. tmpref:=ref;
  1015. make_simple_ref(list,tmpref);
  1016. check_register_size(tosize,reg);
  1017. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1018. internalerror(2011021307);
  1019. { if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1020. fromsize:=tosize;}
  1021. case tosize of
  1022. OS_8,OS_S8:
  1023. if fromsize in [OS_8,OS_S8] then
  1024. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
  1025. else
  1026. internalerror(2013030210);
  1027. OS_16,OS_S16:
  1028. case fromsize of
  1029. OS_8:
  1030. begin
  1031. reg := makeregsize(list, reg, OS_8);
  1032. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1033. setsubreg(reg, R_SUBH);
  1034. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1035. makeregsize(list, reg, OS_16);
  1036. end;
  1037. OS_S8:
  1038. begin
  1039. getcpuregister(list, NR_AX);
  1040. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1041. list.concat(taicpu.op_none(A_CBW));
  1042. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1043. ungetcpuregister(list, NR_AX);
  1044. end;
  1045. OS_16,OS_S16:
  1046. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1047. else
  1048. internalerror(2013030212);
  1049. end;
  1050. OS_32,OS_S32:
  1051. case fromsize of
  1052. OS_8:
  1053. begin
  1054. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1055. reg := makeregsize(list, reg, OS_8);
  1056. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1057. setsubreg(reg, R_SUBH);
  1058. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1059. makeregsize(list, reg, OS_16);
  1060. end;
  1061. OS_S8:
  1062. begin
  1063. getcpuregister(list, NR_AX);
  1064. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1065. getcpuregister(list, NR_DX);
  1066. list.concat(taicpu.op_none(A_CBW));
  1067. list.concat(taicpu.op_none(A_CWD));
  1068. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1069. ungetcpuregister(list, NR_AX);
  1070. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1071. ungetcpuregister(list, NR_DX);
  1072. end;
  1073. OS_16:
  1074. begin
  1075. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1076. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1077. end;
  1078. OS_S16:
  1079. begin
  1080. getcpuregister(list, NR_AX);
  1081. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  1082. getcpuregister(list, NR_DX);
  1083. list.concat(taicpu.op_none(A_CWD));
  1084. ungetcpuregister(list, NR_AX);
  1085. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1086. ungetcpuregister(list, NR_DX);
  1087. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1088. end;
  1089. OS_32,OS_S32:
  1090. begin
  1091. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1092. inc(tmpref.offset, 2);
  1093. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  1094. end;
  1095. else
  1096. internalerror(2013030213);
  1097. end;
  1098. else
  1099. internalerror(2013030211);
  1100. end;
  1101. end;
  1102. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  1103. procedure add_mov(instr: Taicpu);
  1104. begin
  1105. { Notify the register allocator that we have written a move instruction so
  1106. it can try to eliminate it. }
  1107. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1108. add_move_instruction(instr);
  1109. list.concat(instr);
  1110. end;
  1111. begin
  1112. check_register_size(fromsize,reg1);
  1113. check_register_size(tosize,reg2);
  1114. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1115. begin
  1116. if tosize in [OS_32, OS_S32] then
  1117. internalerror(2013031801);
  1118. reg1:=makeregsize(list,reg1,tosize);
  1119. fromsize:=tosize;
  1120. end;
  1121. if (reg1<>reg2) or (fromsize<>tosize) then
  1122. begin
  1123. case tosize of
  1124. OS_8,OS_S8:
  1125. if fromsize in [OS_8,OS_S8] then
  1126. begin
  1127. if reg1<>reg2 then
  1128. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1129. end
  1130. else
  1131. internalerror(2013030210);
  1132. OS_16,OS_S16:
  1133. case fromsize of
  1134. OS_8:
  1135. begin
  1136. reg2 := makeregsize(list, reg2, OS_8);
  1137. if reg1<>reg2 then
  1138. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1139. setsubreg(reg2,R_SUBH);
  1140. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1141. makeregsize(list, reg2, OS_16);
  1142. end;
  1143. OS_S8:
  1144. begin
  1145. getcpuregister(list, NR_AX);
  1146. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1147. list.concat(taicpu.op_none(A_CBW));
  1148. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1149. ungetcpuregister(list, NR_AX);
  1150. end;
  1151. OS_16,OS_S16:
  1152. begin
  1153. if reg1<>reg2 then
  1154. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1155. end
  1156. else
  1157. internalerror(2013030212);
  1158. end;
  1159. OS_32,OS_S32:
  1160. case fromsize of
  1161. OS_8:
  1162. begin
  1163. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
  1164. reg2 := makeregsize(list, reg2, OS_8);
  1165. if reg1<>reg2 then
  1166. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1167. setsubreg(reg2,R_SUBH);
  1168. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1169. makeregsize(list, reg2, OS_16);
  1170. end;
  1171. OS_S8:
  1172. begin
  1173. getcpuregister(list, NR_AX);
  1174. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1175. getcpuregister(list, NR_DX);
  1176. list.concat(taicpu.op_none(A_CBW));
  1177. list.concat(taicpu.op_none(A_CWD));
  1178. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1179. ungetcpuregister(list, NR_AX);
  1180. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1181. ungetcpuregister(list, NR_DX);
  1182. end;
  1183. OS_16:
  1184. begin
  1185. if reg1<>reg2 then
  1186. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1187. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1188. end;
  1189. OS_S16:
  1190. begin
  1191. getcpuregister(list, NR_AX);
  1192. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1193. getcpuregister(list, NR_DX);
  1194. list.concat(taicpu.op_none(A_CWD));
  1195. if reg1<>reg2 then
  1196. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1197. ungetcpuregister(list, NR_AX);
  1198. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1199. ungetcpuregister(list, NR_DX);
  1200. end;
  1201. OS_32,OS_S32:
  1202. begin
  1203. if reg1<>reg2 then
  1204. begin
  1205. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1206. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1207. end;
  1208. end;
  1209. else
  1210. internalerror(2013030213);
  1211. end;
  1212. else
  1213. internalerror(2013030211);
  1214. end;
  1215. end;
  1216. end;
  1217. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  1218. var
  1219. ai : taicpu;
  1220. hreg16 : tregister;
  1221. hl_skip: TAsmLabel;
  1222. invf: TResFlags;
  1223. tmpsize: TCgSize;
  1224. begin
  1225. invf := f;
  1226. inverse_flags(invf);
  1227. case size of
  1228. OS_8,OS_S8:
  1229. begin
  1230. tmpsize:=OS_8;
  1231. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1232. end;
  1233. OS_16,OS_S16,OS_32,OS_S32:
  1234. begin
  1235. tmpsize:=OS_16;
  1236. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  1237. end;
  1238. else
  1239. internalerror(2013123101);
  1240. end;
  1241. current_asmdata.getjumplabel(hl_skip);
  1242. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  1243. ai.SetCondition(flags_to_cond(invf));
  1244. ai.is_jmp:=true;
  1245. list.concat(ai);
  1246. { 16-bit INC is shorter than 8-bit }
  1247. hreg16:=makeregsize(list,reg,OS_16);
  1248. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  1249. a_label(list,hl_skip);
  1250. a_load_reg_reg(list,tmpsize,size,reg,reg);
  1251. end;
  1252. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  1253. var
  1254. tmpreg : tregister;
  1255. begin
  1256. tmpreg:=getintregister(list,size);
  1257. g_flags2reg(list,size,f,tmpreg);
  1258. a_load_reg_ref(list,size,size,tmpreg,ref);
  1259. end;
  1260. procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
  1261. begin
  1262. if localsize>0 then
  1263. list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
  1264. end;
  1265. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  1266. var
  1267. stacksize : longint;
  1268. ret_instr: TAsmOp;
  1269. begin
  1270. if po_far in current_procinfo.procdef.procoptions then
  1271. ret_instr:=A_RETF
  1272. else
  1273. ret_instr:=A_RET;
  1274. { MMX needs to call EMMS }
  1275. if assigned(rg[R_MMXREGISTER]) and
  1276. (rg[R_MMXREGISTER].uses_registers) then
  1277. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1278. { remove stackframe }
  1279. if not nostackframe then
  1280. begin
  1281. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1282. begin
  1283. stacksize:=current_procinfo.calc_stackframe_size;
  1284. if (target_info.stackalign>4) and
  1285. ((stacksize <> 0) or
  1286. (pi_do_call in current_procinfo.flags) or
  1287. { can't detect if a call in this case -> use nostackframe }
  1288. { if you (think you) know what you are doing }
  1289. (po_assembler in current_procinfo.procdef.procoptions)) then
  1290. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1291. if (stacksize<>0) then
  1292. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  1293. end
  1294. else
  1295. begin
  1296. if current_settings.cputype < cpu_186 then
  1297. begin
  1298. list.concat(Taicpu.op_reg_reg(A_MOV, S_W, NR_BP, NR_SP));
  1299. list.concat(Taicpu.op_reg(A_POP, S_W, NR_BP));
  1300. end
  1301. else
  1302. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  1303. end;
  1304. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1305. end;
  1306. { return from interrupt }
  1307. if po_interrupt in current_procinfo.procdef.procoptions then
  1308. begin
  1309. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1310. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1311. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  1312. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  1313. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DX));
  1314. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_CX));
  1315. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_BX));
  1316. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_AX));
  1317. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1318. end
  1319. { Routines with the poclearstack flag set use only a ret }
  1320. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  1321. (not paramanager.use_fixed_stack) then
  1322. begin
  1323. { complex return values are removed from stack in C code PM }
  1324. { but not on win32 }
  1325. { and not for safecall with hidden exceptions, because the result }
  1326. { wich contains the exception is passed in EAX }
  1327. if (target_info.system <> system_i386_win32) and
  1328. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  1329. (tf_safecall_exceptions in target_info.flags)) and
  1330. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  1331. current_procinfo.procdef) then
  1332. list.concat(Taicpu.Op_const(ret_instr,S_W,sizeof(aint)))
  1333. else
  1334. list.concat(Taicpu.Op_none(ret_instr,S_NO));
  1335. end
  1336. { ... also routines with parasize=0 }
  1337. else if (parasize=0) then
  1338. list.concat(Taicpu.Op_none(ret_instr,S_NO))
  1339. else
  1340. begin
  1341. { parameters are limited to 65535 bytes because ret allows only imm16 }
  1342. if (parasize>65535) then
  1343. CGMessage(cg_e_parasize_too_big);
  1344. list.concat(Taicpu.Op_const(ret_instr,S_W,parasize));
  1345. end;
  1346. end;
  1347. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  1348. var
  1349. power : longint;
  1350. opsize : topsize;
  1351. begin
  1352. { get stack space }
  1353. getcpuregister(list,NR_DI);
  1354. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  1355. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  1356. { Now DI contains (high+1). }
  1357. { special case handling for elesize=2:
  1358. set CX = (high+1) instead of CX = (high+1)*elesize.
  1359. This allows us to avoid the SHR later. }
  1360. if elesize=2 then
  1361. begin
  1362. { Now DI contains (high+1). Copy it to CX for later use. }
  1363. getcpuregister(list,NR_CX);
  1364. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1365. end;
  1366. { DI := DI * elesize }
  1367. if (elesize<>1) then
  1368. begin
  1369. if ispowerof2(elesize, power) then
  1370. a_op_const_reg(list,OP_SHL,OS_16,power,NR_DI)
  1371. else
  1372. a_op_const_reg(list,OP_IMUL,OS_16,elesize,NR_DI);
  1373. end;
  1374. if elesize<>2 then
  1375. begin
  1376. { Now DI contains (high+1)*elesize. Copy it to CX for later use. }
  1377. getcpuregister(list,NR_CX);
  1378. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1379. end;
  1380. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  1381. by (size div pagesize)*pagesize, otherwise EDI=size.
  1382. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  1383. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  1384. { align stack on 2 bytes }
  1385. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  1386. { load destination, don't use a_load_reg_reg, that will add a move instruction
  1387. that can confuse the reg allocator }
  1388. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1389. {$ifdef volatile_es}
  1390. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  1391. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  1392. {$endif volatile_es}
  1393. { Allocate SI and load it with source }
  1394. getcpuregister(list,NR_SI);
  1395. a_loadaddr_ref_reg(list,ref,NR_SI);
  1396. { calculate size }
  1397. opsize:=S_B;
  1398. if elesize=2 then
  1399. begin
  1400. opsize:=S_W;
  1401. { CX is already number of words, so no need to SHL/SHR }
  1402. end
  1403. else if (elesize and 1)=0 then
  1404. begin
  1405. opsize:=S_W;
  1406. { CX is number of bytes, convert to words }
  1407. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX))
  1408. end;
  1409. if ts_cld in current_settings.targetswitches then
  1410. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1411. if (opsize=S_B) and not (cs_opt_size in current_settings.optimizerswitches) then
  1412. begin
  1413. { SHR CX,1 moves the lowest (odd/even) bit to the carry flag }
  1414. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX));
  1415. list.concat(Taicpu.op_none(A_REP,S_NO));
  1416. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1417. { ADC CX,CX will set CX to 1 if the number of bytes was odd }
  1418. list.concat(Taicpu.op_reg_reg(A_ADC,S_W,NR_CX,NR_CX));
  1419. list.concat(Taicpu.op_none(A_REP,S_NO));
  1420. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1421. end
  1422. else
  1423. begin
  1424. list.concat(Taicpu.op_none(A_REP,S_NO));
  1425. case opsize of
  1426. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1427. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1428. end;
  1429. end;
  1430. ungetcpuregister(list,NR_DI);
  1431. ungetcpuregister(list,NR_CX);
  1432. ungetcpuregister(list,NR_SI);
  1433. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  1434. that can confuse the reg allocator }
  1435. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  1436. end;
  1437. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  1438. begin
  1439. { Nothing to release }
  1440. end;
  1441. procedure tcg8086.g_exception_reason_save(list : TAsmList; const href : treference);
  1442. begin
  1443. if not paramanager.use_fixed_stack then
  1444. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1445. else
  1446. inherited g_exception_reason_save(list,href);
  1447. end;
  1448. procedure tcg8086.g_exception_reason_save_const(list : TAsmList;const href : treference; a: tcgint);
  1449. begin
  1450. if not paramanager.use_fixed_stack then
  1451. push_const(list,OS_INT,a)
  1452. else
  1453. inherited g_exception_reason_save_const(list,href,a);
  1454. end;
  1455. procedure tcg8086.g_exception_reason_load(list : TAsmList; const href : treference);
  1456. begin
  1457. if not paramanager.use_fixed_stack then
  1458. begin
  1459. cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
  1460. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1461. end
  1462. else
  1463. inherited g_exception_reason_load(list,href);
  1464. end;
  1465. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  1466. begin
  1467. case op of
  1468. OP_ADD :
  1469. begin
  1470. op1:=A_ADD;
  1471. op2:=A_ADC;
  1472. end;
  1473. OP_SUB :
  1474. begin
  1475. op1:=A_SUB;
  1476. op2:=A_SBB;
  1477. end;
  1478. OP_XOR :
  1479. begin
  1480. op1:=A_XOR;
  1481. op2:=A_XOR;
  1482. end;
  1483. OP_OR :
  1484. begin
  1485. op1:=A_OR;
  1486. op2:=A_OR;
  1487. end;
  1488. OP_AND :
  1489. begin
  1490. op1:=A_AND;
  1491. op2:=A_AND;
  1492. end;
  1493. else
  1494. internalerror(200203241);
  1495. end;
  1496. end;
  1497. procedure tcg8086.add_move_instruction(instr: Taicpu);
  1498. begin
  1499. { HACK: when regvars are on, don't notify the register allocator of any
  1500. direct moves to BX, so it doesn't try to coalesce them. Currently,
  1501. direct moves to BX are only used when returning an int64 value in
  1502. AX:BX:CX:DX. This hack fixes a common issue with functions, returning
  1503. int64, for example:
  1504. function RandomFrom(const AValues: array of Int64): Int64;
  1505. begin
  1506. result:=AValues[random(High(AValues)+1)];
  1507. end;
  1508. push bp
  1509. mov bp,sp
  1510. ; Var AValues located in register ireg20w
  1511. ; Var $highAVALUES located in register ireg21w
  1512. ; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
  1513. mov ireg20w,word [bp+6]
  1514. mov ireg21w,word [bp+4]
  1515. ; [3] result:=AValues[random(High(AValues)+1)];
  1516. mov ireg22w,ireg21w
  1517. inc ireg22w
  1518. mov ax,ireg22w
  1519. cwd
  1520. mov ireg23w,ax
  1521. mov ireg24w,dx
  1522. push ireg24w
  1523. push ireg23w
  1524. call SYSTEM_$$_RANDOM$LONGINT$$LONGINT
  1525. mov ireg25w,ax
  1526. mov ireg26w,dx
  1527. mov ireg27w,ireg25w
  1528. mov ireg28w,ireg27w
  1529. mov ireg29w,ireg28w
  1530. mov cl,3
  1531. shl ireg29w,cl
  1532. ; Var $result located in register ireg32w:ireg30w
  1533. mov ireg30w,word [ireg20w+ireg29w]
  1534. mov ireg31w,word [ireg20w+ireg29w+2]
  1535. mov ireg32w,word [ireg20w+ireg29w+4] ; problematic section start
  1536. mov ireg33w,word [ireg20w+ireg29w+6]
  1537. ; [4] end;
  1538. mov bx,ireg32w ; problematic section end
  1539. mov ax,ireg33w
  1540. mov dx,ireg30w
  1541. mov cx,ireg31w
  1542. mov sp,bp
  1543. pop bp
  1544. ret 4
  1545. the problem arises, because the register allocator tries to coalesce
  1546. mov bx,ireg32w
  1547. however, in the references [ireg20w+ireg29w+const], due to the
  1548. constraints of i8086, ireg20w can only be BX (or BP, which isn't available
  1549. to the register allocator, because it's used as a base pointer) }
  1550. if (cs_opt_regvar in current_settings.optimizerswitches) and
  1551. (instr.opcode=A_MOV) and (instr.ops=2) and
  1552. (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
  1553. exit
  1554. else
  1555. inherited add_move_instruction(instr);
  1556. end;
  1557. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1558. var
  1559. hsym : tsym;
  1560. href : treference;
  1561. paraloc : Pcgparalocation;
  1562. return_address_size: Integer;
  1563. begin
  1564. if current_settings.x86memorymodel in x86_far_code_models then
  1565. return_address_size:=4
  1566. else
  1567. return_address_size:=2;
  1568. { calculate the parameter info for the procdef }
  1569. procdef.init_paraloc_info(callerside);
  1570. hsym:=tsym(procdef.parast.Find('self'));
  1571. if not(assigned(hsym) and
  1572. (hsym.typ=paravarsym)) then
  1573. internalerror(200305251);
  1574. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1575. while paraloc<>nil do
  1576. with paraloc^ do
  1577. begin
  1578. case loc of
  1579. LOC_REGISTER:
  1580. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  1581. LOC_REFERENCE:
  1582. begin
  1583. { offset in the wrapper needs to be adjusted for the stored
  1584. return address }
  1585. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  1586. and (reference.index<>NR_SI) then
  1587. begin
  1588. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1589. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  1590. if reference.index=NR_SP then
  1591. reference_reset_base(href,NR_DI,reference.offset+return_address_size+2,sizeof(pint))
  1592. else
  1593. reference_reset_base(href,NR_DI,reference.offset+return_address_size,sizeof(pint));
  1594. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1595. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1596. end
  1597. else
  1598. begin
  1599. reference_reset_base(href,reference.index,reference.offset+return_address_size,sizeof(pint));
  1600. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1601. end;
  1602. end
  1603. else
  1604. internalerror(200309189);
  1605. end;
  1606. paraloc:=next;
  1607. end;
  1608. end;
  1609. procedure tcg8086.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1610. {
  1611. possible calling conventions:
  1612. default stdcall cdecl pascal register
  1613. default(0): OK OK OK OK OK
  1614. virtual(1): OK OK OK OK OK(2)
  1615. (0):
  1616. set self parameter to correct value
  1617. jmp mangledname
  1618. (1): The wrapper code use %eax to reach the virtual method address
  1619. set self to correct value
  1620. move self,%bx
  1621. mov 0(%bx),%bx ; load vmt
  1622. jmp vmtoffs(%bx) ; method offs
  1623. (2): Virtual use values pushed on stack to reach the method address
  1624. so the following code be generated:
  1625. set self to correct value
  1626. push %bx ; allocate space for function address
  1627. push %bx
  1628. push %di
  1629. mov self,%bx
  1630. mov 0(%bx),%bx ; load vmt
  1631. mov vmtoffs(%bx),bx ; method offs
  1632. mov %sp,%di
  1633. mov %bx,4(%di)
  1634. pop %di
  1635. pop %bx
  1636. ret 0; jmp the address
  1637. }
  1638. procedure getselftobx(offs: longint);
  1639. var
  1640. href : treference;
  1641. selfoffsetfromsp : longint;
  1642. begin
  1643. { "mov offset(%sp),%bx" }
  1644. if (procdef.proccalloption<>pocall_register) then
  1645. begin
  1646. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1647. { framepointer is pushed for nested procs }
  1648. if procdef.parast.symtablelevel>normal_function_level then
  1649. selfoffsetfromsp:=2*sizeof(aint)
  1650. else
  1651. selfoffsetfromsp:=sizeof(aint);
  1652. if current_settings.x86memorymodel in x86_far_code_models then
  1653. inc(selfoffsetfromsp,2);
  1654. list.concat(taicpu.op_reg_reg(A_mov,S_W,NR_SP,NR_DI));
  1655. reference_reset_base(href,NR_DI,selfoffsetfromsp+offs+2,2);
  1656. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1657. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1658. end
  1659. else
  1660. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_BX,NR_BX);
  1661. end;
  1662. procedure loadvmttobx;
  1663. var
  1664. href : treference;
  1665. begin
  1666. { mov 0(%bx),%bx ; load vmt}
  1667. reference_reset_base(href,NR_BX,0,2);
  1668. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1669. end;
  1670. procedure loadmethodoffstobx;
  1671. var
  1672. href : treference;
  1673. begin
  1674. if (procdef.extnumber=$ffff) then
  1675. Internalerror(200006139);
  1676. if current_settings.x86memorymodel in x86_far_code_models then
  1677. begin
  1678. { mov vmtseg(%bx),%si ; method seg }
  1679. reference_reset_base(href,NR_BX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)+2,2);
  1680. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_SI);
  1681. end;
  1682. { mov vmtoffs(%bx),%bx ; method offs }
  1683. reference_reset_base(href,NR_BX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),2);
  1684. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1685. end;
  1686. var
  1687. lab : tasmsymbol;
  1688. make_global : boolean;
  1689. href : treference;
  1690. begin
  1691. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1692. Internalerror(200006137);
  1693. if not assigned(procdef.struct) or
  1694. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1695. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1696. Internalerror(200006138);
  1697. if procdef.owner.symtabletype<>ObjectSymtable then
  1698. Internalerror(200109191);
  1699. make_global:=false;
  1700. if (not current_module.is_unit) or
  1701. create_smartlink or
  1702. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1703. make_global:=true;
  1704. if make_global then
  1705. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1706. else
  1707. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1708. { set param1 interface to self }
  1709. g_adjust_self_value(list,procdef,ioffset);
  1710. if (po_virtualmethod in procdef.procoptions) and
  1711. not is_objectpascal_helper(procdef.struct) then
  1712. begin
  1713. { case 1 & case 2 }
  1714. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX)); { allocate space for address}
  1715. if current_settings.x86memorymodel in x86_far_code_models then
  1716. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX));
  1717. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX));
  1718. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1719. if current_settings.x86memorymodel in x86_far_code_models then
  1720. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SI));
  1721. if current_settings.x86memorymodel in x86_far_code_models then
  1722. getselftobx(10)
  1723. else
  1724. getselftobx(6);
  1725. loadvmttobx;
  1726. loadmethodoffstobx;
  1727. { set target address
  1728. "mov %bx,4(%sp)" }
  1729. if current_settings.x86memorymodel in x86_far_code_models then
  1730. reference_reset_base(href,NR_DI,6,2)
  1731. else
  1732. reference_reset_base(href,NR_DI,4,2);
  1733. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1734. list.concat(taicpu.op_reg_ref(A_MOV,S_W,NR_BX,href));
  1735. if current_settings.x86memorymodel in x86_far_code_models then
  1736. begin
  1737. reference_reset_base(href,NR_DI,8,2);
  1738. list.concat(taicpu.op_reg_ref(A_MOV,S_W,NR_SI,href));
  1739. end;
  1740. { load ax? }
  1741. if procdef.proccalloption=pocall_register then
  1742. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_BX,NR_AX));
  1743. { restore register
  1744. pop %di,bx }
  1745. if current_settings.x86memorymodel in x86_far_code_models then
  1746. list.concat(taicpu.op_reg(A_POP,S_W,NR_SI));
  1747. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1748. list.concat(taicpu.op_reg(A_POP,S_W,NR_BX));
  1749. { ret ; jump to the address }
  1750. if current_settings.x86memorymodel in x86_far_code_models then
  1751. list.concat(taicpu.op_none(A_RETF,S_W))
  1752. else
  1753. list.concat(taicpu.op_none(A_RET,S_W));
  1754. end
  1755. { case 0 }
  1756. else
  1757. begin
  1758. lab:=current_asmdata.RefAsmSymbol(procdef.mangledname);
  1759. if current_settings.x86memorymodel in x86_far_code_models then
  1760. begin
  1761. reference_reset_symbol(href,lab,0,sizeof(pint));
  1762. href.refaddr:=addr_far;
  1763. list.concat(taicpu.op_ref(A_JMP,S_NO,href));
  1764. end
  1765. else
  1766. list.concat(taicpu.op_sym(A_JMP,S_NO,lab));
  1767. end;
  1768. List.concat(Tai_symbol_end.Createname(labelname));
  1769. end;
  1770. { ************* 64bit operations ************ }
  1771. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  1772. begin
  1773. case op of
  1774. OP_ADD :
  1775. begin
  1776. op1:=A_ADD;
  1777. op2:=A_ADC;
  1778. end;
  1779. OP_SUB :
  1780. begin
  1781. op1:=A_SUB;
  1782. op2:=A_SBB;
  1783. end;
  1784. OP_XOR :
  1785. begin
  1786. op1:=A_XOR;
  1787. op2:=A_XOR;
  1788. end;
  1789. OP_OR :
  1790. begin
  1791. op1:=A_OR;
  1792. op2:=A_OR;
  1793. end;
  1794. OP_AND :
  1795. begin
  1796. op1:=A_AND;
  1797. op2:=A_AND;
  1798. end;
  1799. else
  1800. internalerror(200203241);
  1801. end;
  1802. end;
  1803. procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  1804. var
  1805. op1,op2 : TAsmOp;
  1806. tempref : treference;
  1807. begin
  1808. if not(op in [OP_NEG,OP_NOT]) then
  1809. begin
  1810. get_64bit_ops(op,op1,op2);
  1811. tempref:=ref;
  1812. tcgx86(cg).make_simple_ref(list,tempref);
  1813. list.concat(taicpu.op_ref_reg(op1,S_W,tempref,reg.reglo));
  1814. inc(tempref.offset,2);
  1815. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reglo)));
  1816. inc(tempref.offset,2);
  1817. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,reg.reghi));
  1818. inc(tempref.offset,2);
  1819. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reghi)));
  1820. end
  1821. else
  1822. begin
  1823. a_load64_ref_reg(list,ref,reg);
  1824. a_op64_reg_reg(list,op,size,reg,reg);
  1825. end;
  1826. end;
  1827. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1828. var
  1829. op1,op2 : TAsmOp;
  1830. begin
  1831. case op of
  1832. OP_NEG :
  1833. begin
  1834. if (regsrc.reglo<>regdst.reglo) then
  1835. a_load64_reg_reg(list,regsrc,regdst);
  1836. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1837. cg.a_op_reg_reg(list,OP_NEG,OS_32,regdst.reglo,regdst.reglo);
  1838. { there's no OP_SBB, so do it directly }
  1839. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  1840. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,GetNextReg(regdst.reghi)));
  1841. exit;
  1842. end;
  1843. OP_NOT :
  1844. begin
  1845. if (regsrc.reglo<>regdst.reglo) then
  1846. a_load64_reg_reg(list,regsrc,regdst);
  1847. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  1848. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1849. exit;
  1850. end;
  1851. end;
  1852. get_64bit_ops(op,op1,op2);
  1853. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  1854. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reglo),GetNextReg(regdst.reglo)));
  1855. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  1856. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reghi),GetNextReg(regdst.reghi)));
  1857. end;
  1858. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1859. var
  1860. op1,op2 : TAsmOp;
  1861. begin
  1862. case op of
  1863. OP_AND,OP_OR,OP_XOR:
  1864. begin
  1865. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  1866. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  1867. end;
  1868. OP_ADD, OP_SUB:
  1869. begin
  1870. // can't use a_op_const_ref because this may use dec/inc
  1871. get_64bit_ops(op,op1,op2);
  1872. if (value and $ffffffffffff) = 0 then
  1873. begin
  1874. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1875. end
  1876. else if (value and $ffffffff) = 0 then
  1877. begin
  1878. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1879. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1880. end
  1881. else if (value and $ffff) = 0 then
  1882. begin
  1883. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  1884. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1885. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1886. end
  1887. else
  1888. begin
  1889. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  1890. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  1891. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1892. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1893. end;
  1894. end;
  1895. else
  1896. internalerror(200204021);
  1897. end;
  1898. end;
  1899. procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  1900. var
  1901. op1,op2 : TAsmOp;
  1902. tempref : treference;
  1903. begin
  1904. tempref:=ref;
  1905. tcgx86(cg).make_simple_ref(list,tempref);
  1906. case op of
  1907. OP_AND,OP_OR,OP_XOR:
  1908. begin
  1909. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  1910. inc(tempref.offset,4);
  1911. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  1912. end;
  1913. OP_ADD, OP_SUB:
  1914. begin
  1915. get_64bit_ops(op,op1,op2);
  1916. // can't use a_op_const_ref because this may use dec/inc
  1917. if (value and $ffffffffffff) = 0 then
  1918. begin
  1919. inc(tempref.offset,6);
  1920. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 48) and $ffff),tempref));
  1921. end
  1922. else if (value and $ffffffff) = 0 then
  1923. begin
  1924. inc(tempref.offset,4);
  1925. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 32) and $ffff),tempref));
  1926. inc(tempref.offset,2);
  1927. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  1928. end
  1929. else if (value and $ffff) = 0 then
  1930. begin
  1931. inc(tempref.offset,2);
  1932. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 16) and $ffff),tempref));
  1933. inc(tempref.offset,2);
  1934. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  1935. inc(tempref.offset,2);
  1936. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  1937. end
  1938. else
  1939. begin
  1940. list.concat(taicpu.op_const_ref(op1,S_W,aint(value and $ffff),tempref));
  1941. inc(tempref.offset,2);
  1942. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 16) and $ffff),tempref));
  1943. inc(tempref.offset,2);
  1944. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  1945. inc(tempref.offset,2);
  1946. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  1947. end;
  1948. end;
  1949. else
  1950. internalerror(200204022);
  1951. end;
  1952. end;
  1953. procedure create_codegen;
  1954. begin
  1955. cg := tcg8086.create;
  1956. cg64 := tcg64f8086.create;
  1957. end;
  1958. end.