cgcpu.pas 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138
  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. tmpsize : tcgsize;
  949. tmpreg : tregister;
  950. tmpref : treference;
  951. begin
  952. tmpref:=ref;
  953. make_simple_ref(list,tmpref);
  954. check_register_size(fromsize,reg);
  955. case tosize of
  956. OS_8,OS_S8:
  957. if fromsize in [OS_8,OS_S8] then
  958. list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
  959. else
  960. internalerror(2013030310);
  961. OS_16,OS_S16:
  962. case fromsize of
  963. OS_8:
  964. begin
  965. reg := makeregsize(list, reg, OS_16);
  966. setsubreg(reg, R_SUBH);
  967. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  968. setsubreg(reg, R_SUBW);
  969. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  970. end;
  971. OS_S8: internalerror(2013052503); { TODO }
  972. OS_16,OS_S16:
  973. begin
  974. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  975. end;
  976. else
  977. internalerror(2013030312);
  978. end;
  979. OS_32,OS_S32:
  980. case fromsize of
  981. OS_8:
  982. begin
  983. reg := makeregsize(list, reg, OS_16);
  984. setsubreg(reg, R_SUBH);
  985. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  986. setsubreg(reg, R_SUBW);
  987. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  988. inc(tmpref.offset, 2);
  989. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  990. end;
  991. OS_S8:
  992. internalerror(2013052501); { TODO }
  993. OS_16:
  994. begin
  995. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  996. inc(tmpref.offset, 2);
  997. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  998. end;
  999. OS_S16:
  1000. internalerror(2013052502); { TODO }
  1001. OS_32,OS_S32:
  1002. begin
  1003. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1004. inc(tmpref.offset, 2);
  1005. list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
  1006. end;
  1007. else
  1008. internalerror(2013030313);
  1009. end;
  1010. else
  1011. internalerror(2013030311);
  1012. end;
  1013. end;
  1014. procedure tcg8086.a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);
  1015. procedure add_mov(instr: Taicpu);
  1016. begin
  1017. { Notify the register allocator that we have written a move instruction so
  1018. it can try to eliminate it. }
  1019. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1020. add_move_instruction(instr);
  1021. list.concat(instr);
  1022. end;
  1023. var
  1024. tmpref : treference;
  1025. begin
  1026. tmpref:=ref;
  1027. make_simple_ref(list,tmpref);
  1028. check_register_size(tosize,reg);
  1029. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1030. internalerror(2011021307);
  1031. { if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1032. fromsize:=tosize;}
  1033. case tosize of
  1034. OS_8,OS_S8:
  1035. if fromsize in [OS_8,OS_S8] then
  1036. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
  1037. else
  1038. internalerror(2013030210);
  1039. OS_16,OS_S16:
  1040. case fromsize of
  1041. OS_8:
  1042. begin
  1043. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  1044. reg := makeregsize(list, reg, OS_8);
  1045. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1046. end;
  1047. OS_S8:
  1048. begin
  1049. getcpuregister(list, NR_AX);
  1050. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1051. list.concat(taicpu.op_none(A_CBW));
  1052. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1053. ungetcpuregister(list, NR_AX);
  1054. end;
  1055. OS_16,OS_S16:
  1056. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1057. else
  1058. internalerror(2013030212);
  1059. end;
  1060. OS_32,OS_S32:
  1061. case fromsize of
  1062. OS_8:
  1063. begin
  1064. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1065. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  1066. reg := makeregsize(list, reg, OS_8);
  1067. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1068. end;
  1069. OS_S8:
  1070. begin
  1071. getcpuregister(list, NR_AX);
  1072. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1073. getcpuregister(list, NR_DX);
  1074. list.concat(taicpu.op_none(A_CBW));
  1075. list.concat(taicpu.op_none(A_CWD));
  1076. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1077. ungetcpuregister(list, NR_AX);
  1078. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1079. ungetcpuregister(list, NR_DX);
  1080. end;
  1081. OS_16:
  1082. begin
  1083. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1084. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1085. end;
  1086. OS_S16:
  1087. begin
  1088. getcpuregister(list, NR_AX);
  1089. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  1090. getcpuregister(list, NR_DX);
  1091. list.concat(taicpu.op_none(A_CWD));
  1092. ungetcpuregister(list, NR_AX);
  1093. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1094. ungetcpuregister(list, NR_DX);
  1095. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1096. end;
  1097. OS_32,OS_S32:
  1098. begin
  1099. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1100. inc(tmpref.offset, 2);
  1101. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  1102. end;
  1103. else
  1104. internalerror(2013030213);
  1105. end;
  1106. else
  1107. internalerror(2013030211);
  1108. end;
  1109. end;
  1110. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  1111. procedure add_mov(instr: Taicpu);
  1112. begin
  1113. { Notify the register allocator that we have written a move instruction so
  1114. it can try to eliminate it. }
  1115. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1116. add_move_instruction(instr);
  1117. list.concat(instr);
  1118. end;
  1119. begin
  1120. check_register_size(fromsize,reg1);
  1121. check_register_size(tosize,reg2);
  1122. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1123. begin
  1124. if tosize in [OS_32, OS_S32] then
  1125. internalerror(2013031801);
  1126. reg1:=makeregsize(list,reg1,tosize);
  1127. fromsize:=tosize;
  1128. end;
  1129. if (reg1<>reg2) then
  1130. begin
  1131. case tosize of
  1132. OS_8,OS_S8:
  1133. if fromsize in [OS_8,OS_S8] then
  1134. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2))
  1135. else
  1136. internalerror(2013030210);
  1137. OS_16,OS_S16:
  1138. case fromsize of
  1139. OS_8:
  1140. begin
  1141. reg2 := makeregsize(list, reg2, OS_8);
  1142. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1143. setsubreg(reg2,R_SUBH);
  1144. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1145. end;
  1146. OS_S8:
  1147. begin
  1148. getcpuregister(list, NR_AX);
  1149. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1150. list.concat(taicpu.op_none(A_CBW));
  1151. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1152. ungetcpuregister(list, NR_AX);
  1153. end;
  1154. OS_16,OS_S16:
  1155. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  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. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1166. setsubreg(reg2,R_SUBH);
  1167. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1168. end;
  1169. OS_S8:
  1170. begin
  1171. getcpuregister(list, NR_AX);
  1172. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1173. getcpuregister(list, NR_DX);
  1174. list.concat(taicpu.op_none(A_CBW));
  1175. list.concat(taicpu.op_none(A_CWD));
  1176. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1177. ungetcpuregister(list, NR_AX);
  1178. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1179. ungetcpuregister(list, NR_DX);
  1180. end;
  1181. OS_16:
  1182. begin
  1183. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1184. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1185. end;
  1186. OS_S16:
  1187. begin
  1188. getcpuregister(list, NR_AX);
  1189. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1190. getcpuregister(list, NR_DX);
  1191. list.concat(taicpu.op_none(A_CWD));
  1192. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1193. ungetcpuregister(list, NR_AX);
  1194. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1195. ungetcpuregister(list, NR_DX);
  1196. end;
  1197. OS_32,OS_S32:
  1198. begin
  1199. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1200. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1201. end;
  1202. else
  1203. internalerror(2013030213);
  1204. end;
  1205. else
  1206. internalerror(2013030211);
  1207. end;
  1208. end;
  1209. end;
  1210. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  1211. var
  1212. ai : taicpu;
  1213. hreg, hreg16 : tregister;
  1214. hl_skip: TAsmLabel;
  1215. invf: TResFlags;
  1216. begin
  1217. hreg:=makeregsize(list,reg,OS_8);
  1218. invf := f;
  1219. inverse_flags(invf);
  1220. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, hreg));
  1221. current_asmdata.getjumplabel(hl_skip);
  1222. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  1223. ai.SetCondition(flags_to_cond(invf));
  1224. ai.is_jmp:=true;
  1225. list.concat(ai);
  1226. { 16-bit INC is shorter than 8-bit }
  1227. hreg16:=makeregsize(list,hreg,OS_16);
  1228. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  1229. a_label(list,hl_skip);
  1230. if reg<>hreg then
  1231. a_load_reg_reg(list,OS_8,size,hreg,reg);
  1232. end;
  1233. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  1234. var
  1235. tmpreg : tregister;
  1236. begin
  1237. tmpreg:=getintregister(list,size);
  1238. g_flags2reg(list,size,f,tmpreg);
  1239. a_load_reg_ref(list,size,size,tmpreg,ref);
  1240. end;
  1241. procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
  1242. begin
  1243. if localsize>0 then
  1244. list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
  1245. end;
  1246. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  1247. var
  1248. stacksize : longint;
  1249. ret_instr: TAsmOp;
  1250. begin
  1251. if po_far in current_procinfo.procdef.procoptions then
  1252. ret_instr:=A_RETF
  1253. else
  1254. ret_instr:=A_RET;
  1255. { MMX needs to call EMMS }
  1256. if assigned(rg[R_MMXREGISTER]) and
  1257. (rg[R_MMXREGISTER].uses_registers) then
  1258. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1259. { remove stackframe }
  1260. if not nostackframe then
  1261. begin
  1262. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1263. begin
  1264. stacksize:=current_procinfo.calc_stackframe_size;
  1265. if (target_info.stackalign>4) and
  1266. ((stacksize <> 0) or
  1267. (pi_do_call in current_procinfo.flags) or
  1268. { can't detect if a call in this case -> use nostackframe }
  1269. { if you (think you) know what you are doing }
  1270. (po_assembler in current_procinfo.procdef.procoptions)) then
  1271. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1272. if (stacksize<>0) then
  1273. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  1274. end
  1275. else
  1276. begin
  1277. if current_settings.cputype < cpu_186 then
  1278. begin
  1279. list.concat(Taicpu.op_reg_reg(A_MOV, S_W, NR_BP, NR_SP));
  1280. list.concat(Taicpu.op_reg(A_POP, S_W, NR_BP));
  1281. end
  1282. else
  1283. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  1284. end;
  1285. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1286. end;
  1287. { return from interrupt }
  1288. if po_interrupt in current_procinfo.procdef.procoptions then
  1289. begin
  1290. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1291. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1292. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  1293. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  1294. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DX));
  1295. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_CX));
  1296. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_BX));
  1297. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_AX));
  1298. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1299. end
  1300. { Routines with the poclearstack flag set use only a ret }
  1301. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  1302. (not paramanager.use_fixed_stack) then
  1303. begin
  1304. { complex return values are removed from stack in C code PM }
  1305. { but not on win32 }
  1306. { and not for safecall with hidden exceptions, because the result }
  1307. { wich contains the exception is passed in EAX }
  1308. if (target_info.system <> system_i386_win32) and
  1309. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  1310. (tf_safecall_exceptions in target_info.flags)) and
  1311. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  1312. current_procinfo.procdef) then
  1313. list.concat(Taicpu.Op_const(ret_instr,S_W,sizeof(aint)))
  1314. else
  1315. list.concat(Taicpu.Op_none(ret_instr,S_NO));
  1316. end
  1317. { ... also routines with parasize=0 }
  1318. else if (parasize=0) then
  1319. list.concat(Taicpu.Op_none(ret_instr,S_NO))
  1320. else
  1321. begin
  1322. { parameters are limited to 65535 bytes because ret allows only imm16 }
  1323. if (parasize>65535) then
  1324. CGMessage(cg_e_parasize_too_big);
  1325. list.concat(Taicpu.Op_const(ret_instr,S_W,parasize));
  1326. end;
  1327. end;
  1328. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  1329. var
  1330. power : longint;
  1331. opsize : topsize;
  1332. begin
  1333. { get stack space }
  1334. getcpuregister(list,NR_DI);
  1335. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  1336. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  1337. { Now DI contains (high+1). }
  1338. { special case handling for elesize=2:
  1339. set CX = (high+1) instead of CX = (high+1)*elesize.
  1340. This allows us to avoid the SHR later. }
  1341. if elesize=2 then
  1342. begin
  1343. { Now DI contains (high+1). Copy it to CX for later use. }
  1344. getcpuregister(list,NR_CX);
  1345. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1346. end;
  1347. { DI := DI * elesize }
  1348. if (elesize<>1) then
  1349. begin
  1350. if ispowerof2(elesize, power) then
  1351. a_op_const_reg(list,OP_SHL,OS_16,power,NR_DI)
  1352. else
  1353. a_op_const_reg(list,OP_IMUL,OS_16,elesize,NR_DI);
  1354. end;
  1355. if elesize<>2 then
  1356. begin
  1357. { Now DI contains (high+1)*elesize. Copy it to CX for later use. }
  1358. getcpuregister(list,NR_CX);
  1359. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1360. end;
  1361. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  1362. by (size div pagesize)*pagesize, otherwise EDI=size.
  1363. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  1364. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  1365. { align stack on 2 bytes }
  1366. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  1367. { load destination, don't use a_load_reg_reg, that will add a move instruction
  1368. that can confuse the reg allocator }
  1369. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1370. {$ifdef volatile_es}
  1371. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  1372. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  1373. {$endif volatile_es}
  1374. { Allocate SI and load it with source }
  1375. getcpuregister(list,NR_SI);
  1376. a_loadaddr_ref_reg(list,ref,NR_SI);
  1377. { calculate size }
  1378. opsize:=S_B;
  1379. if elesize=2 then
  1380. begin
  1381. opsize:=S_W;
  1382. { CX is already number of words, so no need to SHL/SHR }
  1383. end
  1384. else if (elesize and 1)=0 then
  1385. begin
  1386. opsize:=S_W;
  1387. { CX is number of bytes, convert to words }
  1388. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX))
  1389. end;
  1390. if ts_cld in current_settings.targetswitches then
  1391. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1392. if (opsize=S_B) and not (cs_opt_size in current_settings.optimizerswitches) then
  1393. begin
  1394. { SHR CX,1 moves the lowest (odd/even) bit to the carry flag }
  1395. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX));
  1396. list.concat(Taicpu.op_none(A_REP,S_NO));
  1397. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1398. { ADC CX,CX will set CX to 1 if the number of bytes was odd }
  1399. list.concat(Taicpu.op_reg_reg(A_ADC,S_W,NR_CX,NR_CX));
  1400. list.concat(Taicpu.op_none(A_REP,S_NO));
  1401. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1402. end
  1403. else
  1404. begin
  1405. list.concat(Taicpu.op_none(A_REP,S_NO));
  1406. case opsize of
  1407. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1408. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1409. end;
  1410. end;
  1411. ungetcpuregister(list,NR_DI);
  1412. ungetcpuregister(list,NR_CX);
  1413. ungetcpuregister(list,NR_SI);
  1414. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  1415. that can confuse the reg allocator }
  1416. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  1417. end;
  1418. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  1419. begin
  1420. { Nothing to release }
  1421. end;
  1422. procedure tcg8086.g_exception_reason_save(list : TAsmList; const href : treference);
  1423. begin
  1424. if not paramanager.use_fixed_stack then
  1425. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1426. else
  1427. inherited g_exception_reason_save(list,href);
  1428. end;
  1429. procedure tcg8086.g_exception_reason_save_const(list : TAsmList;const href : treference; a: tcgint);
  1430. begin
  1431. if not paramanager.use_fixed_stack then
  1432. push_const(list,OS_INT,a)
  1433. else
  1434. inherited g_exception_reason_save_const(list,href,a);
  1435. end;
  1436. procedure tcg8086.g_exception_reason_load(list : TAsmList; const href : treference);
  1437. begin
  1438. if not paramanager.use_fixed_stack then
  1439. begin
  1440. cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
  1441. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1442. end
  1443. else
  1444. inherited g_exception_reason_load(list,href);
  1445. end;
  1446. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  1447. begin
  1448. case op of
  1449. OP_ADD :
  1450. begin
  1451. op1:=A_ADD;
  1452. op2:=A_ADC;
  1453. end;
  1454. OP_SUB :
  1455. begin
  1456. op1:=A_SUB;
  1457. op2:=A_SBB;
  1458. end;
  1459. OP_XOR :
  1460. begin
  1461. op1:=A_XOR;
  1462. op2:=A_XOR;
  1463. end;
  1464. OP_OR :
  1465. begin
  1466. op1:=A_OR;
  1467. op2:=A_OR;
  1468. end;
  1469. OP_AND :
  1470. begin
  1471. op1:=A_AND;
  1472. op2:=A_AND;
  1473. end;
  1474. else
  1475. internalerror(200203241);
  1476. end;
  1477. end;
  1478. procedure tcg8086.add_move_instruction(instr: Taicpu);
  1479. begin
  1480. { HACK: when regvars are on, don't notify the register allocator of any
  1481. direct moves to BX, so it doesn't try to coalesce them. Currently,
  1482. direct moves to BX are only used when returning an int64 value in
  1483. AX:BX:CX:DX. This hack fixes a common issue with functions, returning
  1484. int64, for example:
  1485. function RandomFrom(const AValues: array of Int64): Int64;
  1486. begin
  1487. result:=AValues[random(High(AValues)+1)];
  1488. end;
  1489. push bp
  1490. mov bp,sp
  1491. ; Var AValues located in register ireg20w
  1492. ; Var $highAVALUES located in register ireg21w
  1493. ; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
  1494. mov ireg20w,word [bp+6]
  1495. mov ireg21w,word [bp+4]
  1496. ; [3] result:=AValues[random(High(AValues)+1)];
  1497. mov ireg22w,ireg21w
  1498. inc ireg22w
  1499. mov ax,ireg22w
  1500. cwd
  1501. mov ireg23w,ax
  1502. mov ireg24w,dx
  1503. push ireg24w
  1504. push ireg23w
  1505. call SYSTEM_$$_RANDOM$LONGINT$$LONGINT
  1506. mov ireg25w,ax
  1507. mov ireg26w,dx
  1508. mov ireg27w,ireg25w
  1509. mov ireg28w,ireg27w
  1510. mov ireg29w,ireg28w
  1511. mov cl,3
  1512. shl ireg29w,cl
  1513. ; Var $result located in register ireg32w:ireg30w
  1514. mov ireg30w,word [ireg20w+ireg29w]
  1515. mov ireg31w,word [ireg20w+ireg29w+2]
  1516. mov ireg32w,word [ireg20w+ireg29w+4] ; problematic section start
  1517. mov ireg33w,word [ireg20w+ireg29w+6]
  1518. ; [4] end;
  1519. mov bx,ireg32w ; problematic section end
  1520. mov ax,ireg33w
  1521. mov dx,ireg30w
  1522. mov cx,ireg31w
  1523. mov sp,bp
  1524. pop bp
  1525. ret 4
  1526. the problem arises, because the register allocator tries to coalesce
  1527. mov bx,ireg32w
  1528. however, in the references [ireg20w+ireg29w+const], due to the
  1529. constraints of i8086, ireg20w can only be BX (or BP, which isn't available
  1530. to the register allocator, because it's used as a base pointer) }
  1531. if (cs_opt_regvar in current_settings.optimizerswitches) and
  1532. (instr.opcode=A_MOV) and (instr.ops=2) and
  1533. (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
  1534. exit
  1535. else
  1536. inherited add_move_instruction(instr);
  1537. end;
  1538. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1539. var
  1540. hsym : tsym;
  1541. href : treference;
  1542. paraloc : Pcgparalocation;
  1543. return_address_size: Integer;
  1544. begin
  1545. if current_settings.x86memorymodel in x86_far_code_models then
  1546. return_address_size:=4
  1547. else
  1548. return_address_size:=2;
  1549. { calculate the parameter info for the procdef }
  1550. procdef.init_paraloc_info(callerside);
  1551. hsym:=tsym(procdef.parast.Find('self'));
  1552. if not(assigned(hsym) and
  1553. (hsym.typ=paravarsym)) then
  1554. internalerror(200305251);
  1555. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1556. while paraloc<>nil do
  1557. with paraloc^ do
  1558. begin
  1559. case loc of
  1560. LOC_REGISTER:
  1561. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  1562. LOC_REFERENCE:
  1563. begin
  1564. { offset in the wrapper needs to be adjusted for the stored
  1565. return address }
  1566. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  1567. and (reference.index<>NR_SI) then
  1568. begin
  1569. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1570. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  1571. if reference.index=NR_SP then
  1572. reference_reset_base(href,NR_DI,reference.offset+return_address_size+2,sizeof(pint))
  1573. else
  1574. reference_reset_base(href,NR_DI,reference.offset+return_address_size,sizeof(pint));
  1575. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1576. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1577. end
  1578. else
  1579. begin
  1580. reference_reset_base(href,reference.index,reference.offset+return_address_size,sizeof(pint));
  1581. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1582. end;
  1583. end
  1584. else
  1585. internalerror(200309189);
  1586. end;
  1587. paraloc:=next;
  1588. end;
  1589. end;
  1590. procedure tcg8086.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1591. {
  1592. possible calling conventions:
  1593. default stdcall cdecl pascal register
  1594. default(0): OK OK OK OK OK
  1595. virtual(1): OK OK OK OK OK(2)
  1596. (0):
  1597. set self parameter to correct value
  1598. jmp mangledname
  1599. (1): The wrapper code use %eax to reach the virtual method address
  1600. set self to correct value
  1601. move self,%bx
  1602. mov 0(%bx),%bx ; load vmt
  1603. jmp vmtoffs(%bx) ; method offs
  1604. (2): Virtual use values pushed on stack to reach the method address
  1605. so the following code be generated:
  1606. set self to correct value
  1607. push %bx ; allocate space for function address
  1608. push %bx
  1609. push %di
  1610. mov self,%bx
  1611. mov 0(%bx),%bx ; load vmt
  1612. mov vmtoffs(%bx),bx ; method offs
  1613. mov %sp,%di
  1614. mov %bx,4(%di)
  1615. pop %di
  1616. pop %bx
  1617. ret 0; jmp the address
  1618. }
  1619. procedure getselftobx(offs: longint);
  1620. var
  1621. href : treference;
  1622. selfoffsetfromsp : longint;
  1623. begin
  1624. { "mov offset(%sp),%bx" }
  1625. if (procdef.proccalloption<>pocall_register) then
  1626. begin
  1627. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1628. { framepointer is pushed for nested procs }
  1629. if procdef.parast.symtablelevel>normal_function_level then
  1630. selfoffsetfromsp:=2*sizeof(aint)
  1631. else
  1632. selfoffsetfromsp:=sizeof(aint);
  1633. if current_settings.x86memorymodel in x86_far_code_models then
  1634. inc(selfoffsetfromsp,2);
  1635. list.concat(taicpu.op_reg_reg(A_mov,S_W,NR_SP,NR_DI));
  1636. reference_reset_base(href,NR_DI,selfoffsetfromsp+offs+2,2);
  1637. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1638. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1639. end
  1640. else
  1641. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_BX,NR_BX);
  1642. end;
  1643. procedure loadvmttobx;
  1644. var
  1645. href : treference;
  1646. begin
  1647. { mov 0(%bx),%bx ; load vmt}
  1648. reference_reset_base(href,NR_BX,0,2);
  1649. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1650. end;
  1651. procedure loadmethodoffstobx;
  1652. var
  1653. href : treference;
  1654. begin
  1655. if (procdef.extnumber=$ffff) then
  1656. Internalerror(200006139);
  1657. if current_settings.x86memorymodel in x86_far_code_models then
  1658. begin
  1659. { mov vmtseg(%bx),%si ; method seg }
  1660. reference_reset_base(href,NR_BX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)+2,2);
  1661. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_SI);
  1662. end;
  1663. { mov vmtoffs(%bx),%bx ; method offs }
  1664. reference_reset_base(href,NR_BX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),2);
  1665. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1666. end;
  1667. var
  1668. lab : tasmsymbol;
  1669. make_global : boolean;
  1670. href : treference;
  1671. begin
  1672. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1673. Internalerror(200006137);
  1674. if not assigned(procdef.struct) or
  1675. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1676. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1677. Internalerror(200006138);
  1678. if procdef.owner.symtabletype<>ObjectSymtable then
  1679. Internalerror(200109191);
  1680. make_global:=false;
  1681. if (not current_module.is_unit) or
  1682. create_smartlink or
  1683. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1684. make_global:=true;
  1685. if make_global then
  1686. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1687. else
  1688. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1689. { set param1 interface to self }
  1690. g_adjust_self_value(list,procdef,ioffset);
  1691. if (po_virtualmethod in procdef.procoptions) and
  1692. not is_objectpascal_helper(procdef.struct) then
  1693. begin
  1694. { case 1 & case 2 }
  1695. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX)); { allocate space for address}
  1696. if current_settings.x86memorymodel in x86_far_code_models then
  1697. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX));
  1698. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX));
  1699. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1700. if current_settings.x86memorymodel in x86_far_code_models then
  1701. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SI));
  1702. if current_settings.x86memorymodel in x86_far_code_models then
  1703. getselftobx(10)
  1704. else
  1705. getselftobx(6);
  1706. loadvmttobx;
  1707. loadmethodoffstobx;
  1708. { set target address
  1709. "mov %bx,4(%sp)" }
  1710. if current_settings.x86memorymodel in x86_far_code_models then
  1711. reference_reset_base(href,NR_DI,6,2)
  1712. else
  1713. reference_reset_base(href,NR_DI,4,2);
  1714. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1715. list.concat(taicpu.op_reg_ref(A_MOV,S_W,NR_BX,href));
  1716. if current_settings.x86memorymodel in x86_far_code_models then
  1717. begin
  1718. reference_reset_base(href,NR_DI,8,2);
  1719. list.concat(taicpu.op_reg_ref(A_MOV,S_W,NR_SI,href));
  1720. end;
  1721. { load ax? }
  1722. if procdef.proccalloption=pocall_register then
  1723. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_BX,NR_AX));
  1724. { restore register
  1725. pop %di,bx }
  1726. if current_settings.x86memorymodel in x86_far_code_models then
  1727. list.concat(taicpu.op_reg(A_POP,S_W,NR_SI));
  1728. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1729. list.concat(taicpu.op_reg(A_POP,S_W,NR_BX));
  1730. { ret ; jump to the address }
  1731. if current_settings.x86memorymodel in x86_far_code_models then
  1732. list.concat(taicpu.op_none(A_RETF,S_W))
  1733. else
  1734. list.concat(taicpu.op_none(A_RET,S_W));
  1735. end
  1736. { case 0 }
  1737. else
  1738. begin
  1739. lab:=current_asmdata.RefAsmSymbol(procdef.mangledname);
  1740. if current_settings.x86memorymodel in x86_far_code_models then
  1741. begin
  1742. reference_reset_symbol(href,lab,0,sizeof(pint));
  1743. href.refaddr:=addr_far;
  1744. list.concat(taicpu.op_ref(A_JMP,S_NO,href));
  1745. end
  1746. else
  1747. list.concat(taicpu.op_sym(A_JMP,S_NO,lab));
  1748. end;
  1749. List.concat(Tai_symbol_end.Createname(labelname));
  1750. end;
  1751. { ************* 64bit operations ************ }
  1752. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  1753. begin
  1754. case op of
  1755. OP_ADD :
  1756. begin
  1757. op1:=A_ADD;
  1758. op2:=A_ADC;
  1759. end;
  1760. OP_SUB :
  1761. begin
  1762. op1:=A_SUB;
  1763. op2:=A_SBB;
  1764. end;
  1765. OP_XOR :
  1766. begin
  1767. op1:=A_XOR;
  1768. op2:=A_XOR;
  1769. end;
  1770. OP_OR :
  1771. begin
  1772. op1:=A_OR;
  1773. op2:=A_OR;
  1774. end;
  1775. OP_AND :
  1776. begin
  1777. op1:=A_AND;
  1778. op2:=A_AND;
  1779. end;
  1780. else
  1781. internalerror(200203241);
  1782. end;
  1783. end;
  1784. procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  1785. var
  1786. op1,op2 : TAsmOp;
  1787. tempref : treference;
  1788. begin
  1789. if not(op in [OP_NEG,OP_NOT]) then
  1790. begin
  1791. get_64bit_ops(op,op1,op2);
  1792. tempref:=ref;
  1793. tcgx86(cg).make_simple_ref(list,tempref);
  1794. list.concat(taicpu.op_ref_reg(op1,S_W,tempref,reg.reglo));
  1795. inc(tempref.offset,2);
  1796. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reglo)));
  1797. inc(tempref.offset,2);
  1798. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,reg.reghi));
  1799. inc(tempref.offset,2);
  1800. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,GetNextReg(reg.reghi)));
  1801. end
  1802. else
  1803. begin
  1804. a_load64_ref_reg(list,ref,reg);
  1805. a_op64_reg_reg(list,op,size,reg,reg);
  1806. end;
  1807. end;
  1808. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1809. var
  1810. op1,op2 : TAsmOp;
  1811. begin
  1812. case op of
  1813. OP_NEG :
  1814. begin
  1815. if (regsrc.reglo<>regdst.reglo) then
  1816. a_load64_reg_reg(list,regsrc,regdst);
  1817. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1818. cg.a_op_reg_reg(list,OP_NEG,OS_32,regdst.reglo,regdst.reglo);
  1819. { there's no OP_SBB, so do it directly }
  1820. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  1821. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,GetNextReg(regdst.reghi)));
  1822. exit;
  1823. end;
  1824. OP_NOT :
  1825. begin
  1826. if (regsrc.reglo<>regdst.reglo) then
  1827. a_load64_reg_reg(list,regsrc,regdst);
  1828. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  1829. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1830. exit;
  1831. end;
  1832. end;
  1833. get_64bit_ops(op,op1,op2);
  1834. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  1835. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reglo),GetNextReg(regdst.reglo)));
  1836. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  1837. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reghi),GetNextReg(regdst.reghi)));
  1838. end;
  1839. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1840. var
  1841. op1,op2 : TAsmOp;
  1842. begin
  1843. case op of
  1844. OP_AND,OP_OR,OP_XOR:
  1845. begin
  1846. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  1847. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  1848. end;
  1849. OP_ADD, OP_SUB:
  1850. begin
  1851. // can't use a_op_const_ref because this may use dec/inc
  1852. get_64bit_ops(op,op1,op2);
  1853. if (value and $ffffffffffff) = 0 then
  1854. begin
  1855. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1856. end
  1857. else if (value and $ffffffff) = 0 then
  1858. begin
  1859. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1860. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1861. end
  1862. else if (value and $ffff) = 0 then
  1863. begin
  1864. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  1865. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1866. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1867. end
  1868. else
  1869. begin
  1870. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  1871. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  1872. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1873. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1874. end;
  1875. end;
  1876. else
  1877. internalerror(200204021);
  1878. end;
  1879. end;
  1880. procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  1881. var
  1882. op1,op2 : TAsmOp;
  1883. tempref : treference;
  1884. begin
  1885. tempref:=ref;
  1886. tcgx86(cg).make_simple_ref(list,tempref);
  1887. case op of
  1888. OP_AND,OP_OR,OP_XOR:
  1889. begin
  1890. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  1891. inc(tempref.offset,4);
  1892. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  1893. end;
  1894. OP_ADD, OP_SUB:
  1895. begin
  1896. get_64bit_ops(op,op1,op2);
  1897. // can't use a_op_const_ref because this may use dec/inc
  1898. if (value and $ffffffffffff) = 0 then
  1899. begin
  1900. inc(tempref.offset,6);
  1901. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 48) and $ffff),tempref));
  1902. end
  1903. else if (value and $ffffffff) = 0 then
  1904. begin
  1905. inc(tempref.offset,4);
  1906. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 32) and $ffff),tempref));
  1907. inc(tempref.offset,2);
  1908. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  1909. end
  1910. else if (value and $ffff) = 0 then
  1911. begin
  1912. inc(tempref.offset,2);
  1913. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 16) and $ffff),tempref));
  1914. inc(tempref.offset,2);
  1915. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  1916. inc(tempref.offset,2);
  1917. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  1918. end
  1919. else
  1920. begin
  1921. list.concat(taicpu.op_const_ref(op1,S_W,aint(value and $ffff),tempref));
  1922. inc(tempref.offset,2);
  1923. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 16) and $ffff),tempref));
  1924. inc(tempref.offset,2);
  1925. list.concat(taicpu.op_const_ref(op2,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. end;
  1930. else
  1931. internalerror(200204022);
  1932. end;
  1933. end;
  1934. procedure create_codegen;
  1935. begin
  1936. cg := tcg8086.create;
  1937. cg64 := tcg64f8086.create;
  1938. end;
  1939. end.