cgcpu.pas 92 KB

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