cgcpu.pas 68 KB

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