cgcpu.pas 71 KB

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