cgcpu.pas 92 KB

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