n8086add.pas 37 KB

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