cgcpu.pas 66 KB

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