n8086add.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Code generation for add nodes on 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 n8086add;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nadd,cpubase,nx86add;
  22. type
  23. { ti8086addnode }
  24. ti8086addnode = class(tx86addnode)
  25. function simplify(forinline: boolean) : tnode;override;
  26. function use_generic_mul32to64: boolean; override;
  27. procedure second_addordinal; override;
  28. procedure second_add64bit;override;
  29. procedure second_addfarpointer;
  30. procedure second_cmp64bit;override;
  31. procedure second_cmp32bit;
  32. procedure second_cmpordinal;override;
  33. procedure second_mul(unsigned: boolean);
  34. end;
  35. implementation
  36. uses
  37. globtype,systems,
  38. cutils,verbose,globals,constexp,
  39. symconst,symdef,symtype,paramgr,defutil,
  40. aasmbase,aasmtai,aasmdata,aasmcpu,
  41. cgbase,procinfo,
  42. ncon,nset,cgutils,tgobj,
  43. cga,ncgutil,cgobj,cg64f32,cgx86,
  44. hlcgobj;
  45. {*****************************************************************************
  46. simplify
  47. *****************************************************************************}
  48. function ti8086addnode.simplify(forinline: boolean): tnode;
  49. var
  50. t : tnode;
  51. lt,rt: tnodetype;
  52. rd,ld: tdef;
  53. rv,lv,v: tconstexprint;
  54. begin
  55. { load easier access variables }
  56. rd:=right.resultdef;
  57. ld:=left.resultdef;
  58. rt:=right.nodetype;
  59. lt:=left.nodetype;
  60. if (
  61. (lt = pointerconstn) and is_farpointer(ld) and
  62. is_constintnode(right) and
  63. (nodetype in [addn,subn])
  64. ) or
  65. (
  66. (rt = pointerconstn) and is_farpointer(rd) and
  67. is_constintnode(left) and
  68. (nodetype=addn)
  69. ) then
  70. begin
  71. t:=nil;
  72. { load values }
  73. case lt of
  74. ordconstn:
  75. lv:=tordconstnode(left).value;
  76. pointerconstn:
  77. lv:=tpointerconstnode(left).value;
  78. niln:
  79. lv:=0;
  80. else
  81. internalerror(2002080202);
  82. end;
  83. case rt of
  84. ordconstn:
  85. rv:=tordconstnode(right).value;
  86. pointerconstn:
  87. rv:=tpointerconstnode(right).value;
  88. niln:
  89. rv:=0;
  90. else
  91. internalerror(2002080203);
  92. end;
  93. case nodetype of
  94. addn:
  95. begin
  96. v:=lv+rv;
  97. if lt=pointerconstn then
  98. t := cpointerconstnode.create((qword(lv) and $FFFF0000) or word(qword(v)),resultdef)
  99. else if rt=pointerconstn then
  100. t := cpointerconstnode.create((qword(rv) and $FFFF0000) or word(qword(v)),resultdef)
  101. else
  102. internalerror(2014040604);
  103. end;
  104. subn:
  105. begin
  106. v:=lv-rv;
  107. if (lt=pointerconstn) then
  108. { pointer-pointer results in an integer }
  109. if (rt=pointerconstn) then
  110. begin
  111. if not(nf_has_pointerdiv in flags) then
  112. internalerror(2008030101);
  113. { todo: implement pointer-pointer as well }
  114. internalerror(2014040607);
  115. //t := cpointerconstnode.create(qword(v),resultdef);
  116. end
  117. else
  118. t := cpointerconstnode.create((qword(lv) and $FFFF0000) or word(qword(v)),resultdef)
  119. else
  120. internalerror(2014040606);
  121. end;
  122. else
  123. internalerror(2014040605);
  124. end;
  125. result:=t;
  126. exit;
  127. end
  128. else
  129. Result:=inherited simplify(forinline);
  130. end;
  131. {*****************************************************************************
  132. use_generic_mul32to64
  133. *****************************************************************************}
  134. function ti8086addnode.use_generic_mul32to64: boolean;
  135. begin
  136. result := True;
  137. end;
  138. { handles all multiplications }
  139. procedure ti8086addnode.second_addordinal;
  140. var
  141. unsigned: boolean;
  142. begin
  143. unsigned:=not(is_signed(left.resultdef)) or
  144. not(is_signed(right.resultdef));
  145. if nodetype=muln then
  146. second_mul(unsigned)
  147. else if is_farpointer(left.resultdef) xor is_farpointer(right.resultdef) then
  148. second_addfarpointer
  149. else
  150. inherited second_addordinal;
  151. end;
  152. {*****************************************************************************
  153. Add64bit
  154. *****************************************************************************}
  155. procedure ti8086addnode.second_add64bit;
  156. var
  157. op : TOpCG;
  158. op1,op2 : TAsmOp;
  159. hregister,
  160. hregister2 : tregister;
  161. hl4 : tasmlabel;
  162. mboverflow,
  163. unsigned:boolean;
  164. r:Tregister;
  165. begin
  166. pass_left_right;
  167. op1:=A_NONE;
  168. op2:=A_NONE;
  169. mboverflow:=false;
  170. unsigned:=((left.resultdef.typ=orddef) and
  171. (torddef(left.resultdef).ordtype=u64bit)) or
  172. ((right.resultdef.typ=orddef) and
  173. (torddef(right.resultdef).ordtype=u64bit));
  174. case nodetype of
  175. addn :
  176. begin
  177. op:=OP_ADD;
  178. mboverflow:=true;
  179. end;
  180. subn :
  181. begin
  182. op:=OP_SUB;
  183. op1:=A_SUB;
  184. op2:=A_SBB;
  185. mboverflow:=true;
  186. end;
  187. xorn:
  188. op:=OP_XOR;
  189. orn:
  190. op:=OP_OR;
  191. andn:
  192. op:=OP_AND;
  193. else
  194. begin
  195. { everything should be handled in pass_1 (JM) }
  196. internalerror(200109051);
  197. end;
  198. end;
  199. { left and right no register? }
  200. { then one must be demanded }
  201. if (left.location.loc<>LOC_REGISTER) then
  202. begin
  203. if (right.location.loc<>LOC_REGISTER) then
  204. begin
  205. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  206. hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  207. cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
  208. location_reset(left.location,LOC_REGISTER,left.location.size);
  209. left.location.register64.reglo:=hregister;
  210. left.location.register64.reghi:=hregister2;
  211. end
  212. else
  213. begin
  214. location_swap(left.location,right.location);
  215. toggleflag(nf_swapped);
  216. end;
  217. end;
  218. { at this point, left.location.loc should be LOC_REGISTER }
  219. if right.location.loc=LOC_REGISTER then
  220. begin
  221. { when swapped another result register }
  222. if (nodetype=subn) and (nf_swapped in flags) then
  223. begin
  224. cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
  225. left.location.register64,
  226. right.location.register64);
  227. location_swap(left.location,right.location);
  228. toggleflag(nf_swapped);
  229. end
  230. else
  231. begin
  232. cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
  233. right.location.register64,
  234. left.location.register64);
  235. end;
  236. end
  237. else
  238. begin
  239. { right.location<>LOC_REGISTER }
  240. if (nodetype=subn) and (nf_swapped in flags) then
  241. begin
  242. r:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  243. cg64.a_load64low_loc_reg(current_asmdata.CurrAsmList,right.location,r);
  244. emit_reg_reg(op1,S_W,left.location.register64.reglo,r);
  245. emit_reg_reg(op2,S_W,GetNextReg(left.location.register64.reglo),GetNextReg(r));
  246. emit_reg_reg(A_MOV,S_W,r,left.location.register64.reglo);
  247. emit_reg_reg(A_MOV,S_W,GetNextReg(r),GetNextReg(left.location.register64.reglo));
  248. cg64.a_load64high_loc_reg(current_asmdata.CurrAsmList,right.location,r);
  249. { the carry flag is still ok }
  250. emit_reg_reg(op2,S_W,left.location.register64.reghi,r);
  251. emit_reg_reg(op2,S_W,GetNextReg(left.location.register64.reghi),GetNextReg(r));
  252. emit_reg_reg(A_MOV,S_W,r,left.location.register64.reghi);
  253. emit_reg_reg(A_MOV,S_W,GetNextReg(r),GetNextReg(left.location.register64.reghi));
  254. end
  255. else
  256. begin
  257. cg64.a_op64_loc_reg(current_asmdata.CurrAsmList,op,location.size,right.location,
  258. left.location.register64);
  259. end;
  260. location_freetemp(current_asmdata.CurrAsmList,right.location);
  261. end;
  262. { only in case of overflow operations }
  263. { produce overflow code }
  264. { we must put it here directly, because sign of operation }
  265. { is in unsigned VAR!! }
  266. if mboverflow then
  267. begin
  268. if cs_check_overflow in current_settings.localswitches then
  269. begin
  270. current_asmdata.getjumplabel(hl4);
  271. if unsigned then
  272. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4)
  273. else
  274. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl4);
  275. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
  276. cg.a_label(current_asmdata.CurrAsmList,hl4);
  277. end;
  278. end;
  279. location_copy(location,left.location);
  280. end;
  281. procedure ti8086addnode.second_addfarpointer;
  282. var
  283. tmpreg : tregister;
  284. pointernode: tnode;
  285. begin
  286. pass_left_right;
  287. force_reg_left_right(false,true);
  288. set_result_location_reg;
  289. if (left.resultdef.typ=pointerdef) and (right.resultdef.typ<>pointerdef) then
  290. pointernode:=left
  291. else if (left.resultdef.typ<>pointerdef) and (right.resultdef.typ=pointerdef) then
  292. pointernode:=right
  293. else
  294. internalerror(2014040601);
  295. if not (nodetype in [addn,subn]) then
  296. internalerror(2014040602);
  297. if nodetype=addn then
  298. begin
  299. if (right.location.loc<>LOC_CONSTANT) then
  300. begin
  301. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
  302. left.location.register,right.location.register,location.register);
  303. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  304. GetNextReg(pointernode.location.register),GetNextReg(location.register));
  305. end
  306. else
  307. begin
  308. if pointernode=left then
  309. begin
  310. { farptr_reg + int_const }
  311. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
  312. right.location.value,left.location.register,location.register);
  313. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  314. GetNextReg(left.location.register),GetNextReg(location.register));
  315. end
  316. else
  317. begin
  318. { int_reg + farptr_const }
  319. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  320. hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,
  321. right.location.value,tmpreg);
  322. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
  323. left.location.register,tmpreg,location.register);
  324. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  325. GetNextReg(tmpreg),GetNextReg(location.register));
  326. end;
  327. end;
  328. end
  329. else { subtract is a special case since its not commutative }
  330. begin
  331. if (nf_swapped in flags) then
  332. swapleftright;
  333. { left can only be a pointer in this case, since (int-pointer) is not supported }
  334. if pointernode<>left then
  335. internalerror(2014040603);
  336. if left.location.loc<>LOC_CONSTANT then
  337. begin
  338. if right.location.loc<>LOC_CONSTANT then
  339. begin
  340. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
  341. right.location.register,left.location.register,location.register);
  342. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  343. GetNextReg(pointernode.location.register),GetNextReg(location.register));
  344. end
  345. else
  346. begin
  347. { farptr_reg - int_const }
  348. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
  349. right.location.value,left.location.register,location.register);
  350. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  351. GetNextReg(left.location.register),GetNextReg(location.register));
  352. end;
  353. end
  354. else
  355. begin
  356. { farptr_const - int_reg }
  357. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  358. hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,
  359. left.location.value,tmpreg);
  360. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
  361. right.location.register,tmpreg,location.register);
  362. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
  363. GetNextReg(tmpreg),GetNextReg(location.register));
  364. end;
  365. end;
  366. end;
  367. procedure ti8086addnode.second_cmp64bit;
  368. var
  369. hregister,
  370. hregister2 : tregister;
  371. href : treference;
  372. unsigned : boolean;
  373. procedure firstjmp64bitcmp;
  374. var
  375. oldnodetype : tnodetype;
  376. begin
  377. {$ifdef OLDREGVARS}
  378. load_all_regvars(current_asmdata.CurrAsmList);
  379. {$endif OLDREGVARS}
  380. { the jump the sequence is a little bit hairy }
  381. case nodetype of
  382. ltn,gtn:
  383. begin
  384. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  385. { cheat a little bit for the negative test }
  386. toggleflag(nf_swapped);
  387. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  388. toggleflag(nf_swapped);
  389. end;
  390. lten,gten:
  391. begin
  392. oldnodetype:=nodetype;
  393. if nodetype=lten then
  394. nodetype:=ltn
  395. else
  396. nodetype:=gtn;
  397. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  398. { cheat for the negative test }
  399. if nodetype=ltn then
  400. nodetype:=gtn
  401. else
  402. nodetype:=ltn;
  403. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  404. nodetype:=oldnodetype;
  405. end;
  406. equaln:
  407. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  408. unequaln:
  409. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  410. end;
  411. end;
  412. procedure middlejmp64bitcmp;
  413. var
  414. oldnodetype : tnodetype;
  415. begin
  416. {$ifdef OLDREGVARS}
  417. load_all_regvars(current_asmdata.CurrAsmList);
  418. {$endif OLDREGVARS}
  419. { the jump the sequence is a little bit hairy }
  420. case nodetype of
  421. ltn,gtn:
  422. begin
  423. { the comparisaion of the low word have to be }
  424. { always unsigned! }
  425. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
  426. { cheat a little bit for the negative test }
  427. toggleflag(nf_swapped);
  428. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrFalseLabel);
  429. toggleflag(nf_swapped);
  430. end;
  431. lten,gten:
  432. begin
  433. oldnodetype:=nodetype;
  434. if nodetype=lten then
  435. nodetype:=ltn
  436. else
  437. nodetype:=gtn;
  438. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
  439. { cheat for the negative test }
  440. if nodetype=ltn then
  441. nodetype:=gtn
  442. else
  443. nodetype:=ltn;
  444. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrFalseLabel);
  445. nodetype:=oldnodetype;
  446. end;
  447. equaln:
  448. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  449. unequaln:
  450. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  451. end;
  452. end;
  453. procedure lastjmp64bitcmp;
  454. begin
  455. { the jump the sequence is a little bit hairy }
  456. case nodetype of
  457. ltn,gtn,lten,gten:
  458. begin
  459. { the comparisaion of the low word have to be }
  460. { always unsigned! }
  461. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
  462. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  463. end;
  464. equaln:
  465. begin
  466. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  467. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  468. end;
  469. unequaln:
  470. begin
  471. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  472. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  473. end;
  474. end;
  475. end;
  476. begin
  477. pass_left_right;
  478. unsigned:=((left.resultdef.typ=orddef) and
  479. (torddef(left.resultdef).ordtype=u64bit)) or
  480. ((right.resultdef.typ=orddef) and
  481. (torddef(right.resultdef).ordtype=u64bit));
  482. { left and right no register? }
  483. { then one must be demanded }
  484. if (left.location.loc<>LOC_REGISTER) then
  485. begin
  486. if (right.location.loc<>LOC_REGISTER) then
  487. begin
  488. { we can reuse a CREGISTER for comparison }
  489. if (left.location.loc<>LOC_CREGISTER) then
  490. begin
  491. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  492. hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  493. cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
  494. location_freetemp(current_asmdata.CurrAsmList,left.location);
  495. location_reset(left.location,LOC_REGISTER,left.location.size);
  496. left.location.register64.reglo:=hregister;
  497. left.location.register64.reghi:=hregister2;
  498. end;
  499. end
  500. else
  501. begin
  502. location_swap(left.location,right.location);
  503. toggleflag(nf_swapped);
  504. end;
  505. end;
  506. { at this point, left.location.loc should be LOC_REGISTER }
  507. if right.location.loc=LOC_REGISTER then
  508. begin
  509. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register64.reghi),GetNextReg(left.location.register64.reghi));
  510. firstjmp64bitcmp;
  511. emit_reg_reg(A_CMP,S_W,right.location.register64.reghi,left.location.register64.reghi);
  512. middlejmp64bitcmp;
  513. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register64.reglo),GetNextReg(left.location.register64.reglo));
  514. middlejmp64bitcmp;
  515. emit_reg_reg(A_CMP,S_W,right.location.register64.reglo,left.location.register64.reglo);
  516. lastjmp64bitcmp;
  517. end
  518. else
  519. begin
  520. case right.location.loc of
  521. LOC_CREGISTER :
  522. begin
  523. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register64.reghi),GetNextReg(left.location.register64.reghi));
  524. firstjmp64bitcmp;
  525. emit_reg_reg(A_CMP,S_W,right.location.register64.reghi,left.location.register64.reghi);
  526. middlejmp64bitcmp;
  527. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register64.reglo),GetNextReg(left.location.register64.reglo));
  528. middlejmp64bitcmp;
  529. emit_reg_reg(A_CMP,S_W,right.location.register64.reglo,left.location.register64.reglo);
  530. lastjmp64bitcmp;
  531. end;
  532. LOC_CREFERENCE,
  533. LOC_REFERENCE :
  534. begin
  535. tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,right.location.reference);
  536. href:=right.location.reference;
  537. inc(href.offset,6);
  538. emit_ref_reg(A_CMP,S_W,href,GetNextReg(left.location.register64.reghi));
  539. firstjmp64bitcmp;
  540. dec(href.offset,2);
  541. emit_ref_reg(A_CMP,S_W,href,left.location.register64.reghi);
  542. middlejmp64bitcmp;
  543. dec(href.offset,2);
  544. emit_ref_reg(A_CMP,S_W,href,GetNextReg(left.location.register64.reglo));
  545. middlejmp64bitcmp;
  546. emit_ref_reg(A_CMP,S_W,right.location.reference,left.location.register64.reglo);
  547. lastjmp64bitcmp;
  548. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  549. location_freetemp(current_asmdata.CurrAsmList,right.location);
  550. end;
  551. LOC_CONSTANT :
  552. begin
  553. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 48) and $FFFF),GetNextReg(left.location.register64.reghi)));
  554. firstjmp64bitcmp;
  555. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 32) and $FFFF),left.location.register64.reghi));
  556. middlejmp64bitcmp;
  557. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 16) and $FFFF),GetNextReg(left.location.register64.reglo)));
  558. middlejmp64bitcmp;
  559. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint(right.location.value64 and $FFFF),left.location.register64.reglo));
  560. lastjmp64bitcmp;
  561. end;
  562. else
  563. internalerror(200203282);
  564. end;
  565. end;
  566. { we have LOC_JUMP as result }
  567. location_reset(location,LOC_JUMP,OS_NO)
  568. end;
  569. procedure ti8086addnode.second_cmp32bit;
  570. var
  571. hregister : tregister;
  572. href : treference;
  573. unsigned : boolean;
  574. procedure firstjmp32bitcmp;
  575. var
  576. oldnodetype : tnodetype;
  577. begin
  578. {$ifdef OLDREGVARS}
  579. load_all_regvars(current_asmdata.CurrAsmList);
  580. {$endif OLDREGVARS}
  581. { the jump the sequence is a little bit hairy }
  582. case nodetype of
  583. ltn,gtn:
  584. begin
  585. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  586. { cheat a little bit for the negative test }
  587. toggleflag(nf_swapped);
  588. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  589. toggleflag(nf_swapped);
  590. end;
  591. lten,gten:
  592. begin
  593. oldnodetype:=nodetype;
  594. if nodetype=lten then
  595. nodetype:=ltn
  596. else
  597. nodetype:=gtn;
  598. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  599. { cheat for the negative test }
  600. if nodetype=ltn then
  601. nodetype:=gtn
  602. else
  603. nodetype:=ltn;
  604. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  605. nodetype:=oldnodetype;
  606. end;
  607. equaln:
  608. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  609. unequaln:
  610. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  611. end;
  612. end;
  613. procedure secondjmp32bitcmp;
  614. begin
  615. { the jump the sequence is a little bit hairy }
  616. case nodetype of
  617. ltn,gtn,lten,gten:
  618. begin
  619. { the comparisaion of the low dword have to be }
  620. { always unsigned! }
  621. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
  622. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  623. end;
  624. equaln:
  625. begin
  626. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  627. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  628. end;
  629. unequaln:
  630. begin
  631. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  632. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  633. end;
  634. end;
  635. end;
  636. begin
  637. pass_left_right;
  638. unsigned:=((left.resultdef.typ=orddef) and
  639. (torddef(left.resultdef).ordtype=u32bit)) or
  640. ((right.resultdef.typ=orddef) and
  641. (torddef(right.resultdef).ordtype=u32bit));
  642. { left and right no register? }
  643. { then one must be demanded }
  644. if (left.location.loc<>LOC_REGISTER) then
  645. begin
  646. if (right.location.loc<>LOC_REGISTER) then
  647. begin
  648. { we can reuse a CREGISTER for comparison }
  649. if (left.location.loc<>LOC_CREGISTER) then
  650. begin
  651. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  652. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_32,left.location,hregister);
  653. location_freetemp(current_asmdata.CurrAsmList,left.location);
  654. location_reset(left.location,LOC_REGISTER,left.location.size);
  655. left.location.register:=hregister;
  656. end;
  657. end
  658. else
  659. begin
  660. location_swap(left.location,right.location);
  661. toggleflag(nf_swapped);
  662. end;
  663. end;
  664. { at this point, left.location.loc should be LOC_REGISTER }
  665. if right.location.loc=LOC_REGISTER then
  666. begin
  667. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register),GetNextReg(left.location.register));
  668. firstjmp32bitcmp;
  669. emit_reg_reg(A_CMP,S_W,right.location.register,left.location.register);
  670. secondjmp32bitcmp;
  671. end
  672. else
  673. begin
  674. case right.location.loc of
  675. LOC_CREGISTER :
  676. begin
  677. emit_reg_reg(A_CMP,S_W,GetNextReg(right.location.register),GetNextReg(left.location.register));
  678. firstjmp32bitcmp;
  679. emit_reg_reg(A_CMP,S_W,right.location.register,left.location.register);
  680. secondjmp32bitcmp;
  681. end;
  682. LOC_CREFERENCE,
  683. LOC_REFERENCE :
  684. begin
  685. tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,right.location.reference);
  686. href:=right.location.reference;
  687. inc(href.offset,2);
  688. emit_ref_reg(A_CMP,S_W,href,GetNextReg(left.location.register));
  689. firstjmp32bitcmp;
  690. dec(href.offset,2);
  691. emit_ref_reg(A_CMP,S_W,href,left.location.register);
  692. secondjmp32bitcmp;
  693. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  694. location_freetemp(current_asmdata.CurrAsmList,right.location);
  695. end;
  696. LOC_CONSTANT :
  697. begin
  698. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value shr 16) and $FFFF),GetNextReg(left.location.register)));
  699. firstjmp32bitcmp;
  700. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint(right.location.value and $FFFF),left.location.register));
  701. secondjmp32bitcmp;
  702. end;
  703. else
  704. internalerror(200203282);
  705. end;
  706. end;
  707. { we have LOC_JUMP as result }
  708. location_reset(location,LOC_JUMP,OS_NO)
  709. end;
  710. procedure ti8086addnode.second_cmpordinal;
  711. begin
  712. if is_32bit(left.resultdef) or is_farpointer(left.resultdef) or is_hugepointer(left.resultdef) then
  713. second_cmp32bit
  714. else
  715. inherited second_cmpordinal;
  716. end;
  717. {*****************************************************************************
  718. x86 MUL
  719. *****************************************************************************}
  720. procedure ti8086addnode.second_mul(unsigned: boolean);
  721. var reg:Tregister;
  722. ref:Treference;
  723. use_ref:boolean;
  724. hl4 : tasmlabel;
  725. const
  726. asmops: array[boolean] of tasmop = (A_IMUL, A_MUL);
  727. begin
  728. pass_left_right;
  729. { MUL is faster than IMUL on the 8086 & 8088 (and equal in speed on 286+),
  730. but it's only safe to use in place of IMUL when overflow checking is off
  731. and we're doing a 16-bit>16-bit multiplication }
  732. if not (cs_check_overflow in current_settings.localswitches) and
  733. (not is_32bitint(resultdef)) then
  734. unsigned:=true;
  735. {The location.register will be filled in later (JM)}
  736. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  737. { Mul supports registers and references, so if not register/reference,
  738. load the location into a register. }
  739. use_ref:=false;
  740. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  741. reg:=left.location.register
  742. else if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  743. begin
  744. tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
  745. ref:=left.location.reference;
  746. use_ref:=true;
  747. end
  748. else
  749. begin
  750. {LOC_CONSTANT for example.}
  751. reg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  752. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,osuinttype,left.location,reg);
  753. end;
  754. {Allocate AX.}
  755. cg.getcpuregister(current_asmdata.CurrAsmList,NR_AX);
  756. {Load the right value.}
  757. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,NR_AX);
  758. {Also allocate DX, since it is also modified by a mul (JM).}
  759. cg.getcpuregister(current_asmdata.CurrAsmList,NR_DX);
  760. if use_ref then
  761. emit_ref(asmops[unsigned],S_W,ref)
  762. else
  763. emit_reg(asmops[unsigned],S_W,reg);
  764. if (cs_check_overflow in current_settings.localswitches) and
  765. { 16->32 bit cannot overflow }
  766. (not is_32bitint(resultdef)) then
  767. begin
  768. current_asmdata.getjumplabel(hl4);
  769. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4);
  770. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
  771. cg.a_label(current_asmdata.CurrAsmList,hl4);
  772. end;
  773. {Free AX,DX}
  774. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_DX);
  775. if is_32bitint(resultdef) then
  776. begin
  777. {Allocate an imaginary 32-bit register, which consists of a pair of
  778. 16-bit registers and store DX:AX into it}
  779. location.register := cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  780. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_DX,GetNextReg(location.register));
  781. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_AX);
  782. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_AX,location.register);
  783. end
  784. else
  785. begin
  786. {Allocate a new register and store the result in AX in it.}
  787. location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  788. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_AX);
  789. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_AX,location.register);
  790. end;
  791. location_freetemp(current_asmdata.CurrAsmList,left.location);
  792. location_freetemp(current_asmdata.CurrAsmList,right.location);
  793. end;
  794. begin
  795. caddnode:=ti8086addnode;
  796. end.