ncgflw.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate assembler for nodes that influence the flow which are
  5. the same for all (most?) processors
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ncgflw;
  20. {$i defines.inc}
  21. interface
  22. uses
  23. node,nflw;
  24. type
  25. tcgwhilerepeatnode = class(twhilerepeatnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgifnode = class(tifnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgfornode = class(tfornode)
  32. procedure pass_2;override;
  33. end;
  34. tcgexitnode = class(texitnode)
  35. procedure pass_2;override;
  36. end;
  37. tcgbreaknode = class(tbreaknode)
  38. procedure pass_2;override;
  39. end;
  40. tcgcontinuenode = class(tcontinuenode)
  41. procedure pass_2;override;
  42. end;
  43. tcggotonode = class(tgotonode)
  44. procedure pass_2;override;
  45. end;
  46. tcglabelnode = class(tlabelnode)
  47. procedure pass_2;override;
  48. end;
  49. implementation
  50. uses
  51. verbose,globals,systems,
  52. symconst,symdef,symsym,aasm,types,
  53. cgbase,temp_gen,pass_2,
  54. cpubase,cpuasm,cpuinfo,
  55. nld,ncon,
  56. cga,tgcpu,
  57. {$ifdef i386}
  58. n386util,
  59. {$endif}
  60. regvars,cgobj,cgcpu;
  61. {*****************************************************************************
  62. Second_While_RepeatN
  63. *****************************************************************************}
  64. procedure tcgwhilerepeatnode.pass_2;
  65. var
  66. lcont,lbreak,lloop,
  67. oldclabel,oldblabel : tasmlabel;
  68. otlabel,oflabel : tasmlabel;
  69. begin
  70. getlabel(lloop);
  71. getlabel(lcont);
  72. getlabel(lbreak);
  73. { arrange continue and breaklabels: }
  74. oldclabel:=aktcontinuelabel;
  75. oldblabel:=aktbreaklabel;
  76. load_all_regvars(exprasmlist);
  77. { handling code at the end as it is much more efficient, and makes
  78. while equal to repeat loop, only the end true/false is swapped (PFV) }
  79. if nodetype=whilen then
  80. cg.a_jmp_cond(exprasmlist,OC_None,lcont);
  81. { align loop target }
  82. exprasmList.concat(Tai_align.Create(aktalignment.loopalign));
  83. cg.a_label(exprasmlist,lloop);
  84. aktcontinuelabel:=lcont;
  85. aktbreaklabel:=lbreak;
  86. cleartempgen;
  87. if assigned(right) then
  88. secondpass(right);
  89. load_all_regvars(exprasmlist);
  90. cg.a_label(exprasmlist,lcont);
  91. otlabel:=truelabel;
  92. oflabel:=falselabel;
  93. if nodetype=whilen then
  94. begin
  95. truelabel:=lloop;
  96. falselabel:=lbreak;
  97. end
  98. { repeatn }
  99. else
  100. begin
  101. truelabel:=lbreak;
  102. falselabel:=lloop;
  103. end;
  104. cleartempgen;
  105. secondpass(left);
  106. load_all_regvars(exprasmlist);
  107. maketojumpbool(left);
  108. cg.a_label(exprasmlist,lbreak);
  109. truelabel:=otlabel;
  110. falselabel:=oflabel;
  111. aktcontinuelabel:=oldclabel;
  112. aktbreaklabel:=oldblabel;
  113. { a break/continue in a while/repeat block can't be seen outside }
  114. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  115. end;
  116. {*****************************************************************************
  117. tcgIFNODE
  118. *****************************************************************************}
  119. procedure tcgifnode.pass_2;
  120. var
  121. hl,otlabel,oflabel : tasmlabel;
  122. begin
  123. otlabel:=truelabel;
  124. oflabel:=falselabel;
  125. getlabel(truelabel);
  126. getlabel(falselabel);
  127. cleartempgen;
  128. secondpass(left);
  129. load_all_regvars(exprasmlist);
  130. maketojumpbool(left);
  131. if assigned(right) then
  132. begin
  133. cg.a_label(exprasmlist,truelabel);
  134. cleartempgen;
  135. secondpass(right);
  136. { automatically done for blocks, but not for statements (JM) }
  137. load_all_regvars(exprasmlist);
  138. end;
  139. if assigned(t1) then
  140. begin
  141. if assigned(right) then
  142. begin
  143. getlabel(hl);
  144. { do go back to if line !! }
  145. aktfilepos:=exprasmList.getlasttaifilepos^;
  146. cg.a_jmp_cond(exprasmlist,OC_None,hl);
  147. end;
  148. cg.a_label(exprasmlist,falselabel);
  149. cleartempgen;
  150. secondpass(t1);
  151. load_all_regvars(exprasmlist);
  152. if assigned(right) then
  153. cg.a_label(exprasmlist,hl);
  154. end
  155. else
  156. begin
  157. cg.a_label(exprasmlist,falselabel);
  158. end;
  159. if not(assigned(right)) then
  160. begin
  161. cg.a_label(exprasmlist,truelabel);
  162. end;
  163. truelabel:=otlabel;
  164. falselabel:=oflabel;
  165. end;
  166. {*****************************************************************************
  167. SecondFor
  168. *****************************************************************************}
  169. procedure tcgfornode.pass_2;
  170. var
  171. l3,oldclabel,oldblabel : tasmlabel;
  172. omitfirstcomp,temptovalue : boolean;
  173. hs : byte;
  174. temp1 : treference;
  175. hop : topcg;
  176. hcond : topcmp;
  177. opsize : tcgsize;
  178. count_var_is_signed : boolean;
  179. begin
  180. oldclabel:=aktcontinuelabel;
  181. oldblabel:=aktbreaklabel;
  182. getlabel(aktcontinuelabel);
  183. getlabel(aktbreaklabel);
  184. getlabel(l3);
  185. { could we spare the first comparison ? }
  186. omitfirstcomp:=false;
  187. if right.nodetype=ordconstn then
  188. if tassignmentnode(left).right.nodetype=ordconstn then
  189. omitfirstcomp:=((nf_backward in flags) and
  190. (tordconstnode(tassignmentnode(left).right).value>=tordconstnode(right).value))
  191. or (not(nf_backward in flags) and
  192. (tordconstnode(tassignmentnode(left).right).value<=tordconstnode(right).value));
  193. { only calculate reference }
  194. cleartempgen;
  195. secondpass(t2);
  196. hs := t2.resulttype.def.size;
  197. opsize := def_cgsize(t2.resulttype.def);
  198. { first set the to value
  199. because the count var can be in the expression !! }
  200. cleartempgen;
  201. secondpass(right);
  202. { calculate pointer value and check if changeable and if so }
  203. { load into temporary variable }
  204. if right.nodetype<>ordconstn then
  205. begin
  206. temp1.symbol:=nil;
  207. gettempofsizereference(hs,temp1);
  208. temptovalue:=true;
  209. if (right.location.loc=LOC_REGISTER) or
  210. (right.location.loc=LOC_CREGISTER) then
  211. begin
  212. cg.a_load_reg_ref(exprasmlist,opsize,
  213. right.location.register,temp1);
  214. ungetregister(right.location.register);
  215. end
  216. else
  217. cg.g_concatcopy(exprasmlist,right.location.reference,temp1,
  218. hs,true,false);
  219. end
  220. else
  221. temptovalue:=false;
  222. { produce start assignment }
  223. cleartempgen;
  224. secondpass(left);
  225. count_var_is_signed:=is_signed(torddef(t2.resulttype.def));
  226. if nf_backward in flags then
  227. if count_var_is_signed then
  228. hcond:=OC_LT
  229. else
  230. hcond:=OC_B
  231. else
  232. if count_var_is_signed then
  233. hcond:=OC_GT
  234. else
  235. hcond:=OC_A;
  236. load_all_regvars(exprasmlist);
  237. if temptovalue then
  238. begin
  239. cg.a_cmp_ref_loc_label(exprasmlist,opsize,hcond,
  240. temp1,t2.location,aktbreaklabel);
  241. end
  242. else
  243. begin
  244. if not(omitfirstcomp) then
  245. begin
  246. cg.a_cmp_const_loc_label(exprasmlist,opsize,hcond,
  247. aword(tordconstnode(right).value),
  248. t2.location,aktbreaklabel);
  249. end;
  250. end;
  251. { align loop target }
  252. exprasmList.concat(Tai_align.Create(aktalignment.loopalign));
  253. cg.a_label(exprasmlist,l3);
  254. { help register must not be in instruction block }
  255. cleartempgen;
  256. if assigned(t1) then
  257. begin
  258. secondpass(t1);
  259. load_all_regvars(exprasmlist);
  260. end;
  261. cg.a_label(exprasmlist,aktcontinuelabel);
  262. { makes no problems there }
  263. cleartempgen;
  264. if nf_backward in flags then
  265. if count_var_is_signed then
  266. hcond:=OC_LTE
  267. else
  268. hcond:=OC_BE
  269. else
  270. if count_var_is_signed then
  271. hcond:=OC_GTE
  272. else
  273. hcond:=OC_AE;
  274. load_all_regvars(exprasmlist);
  275. { produce comparison and the corresponding }
  276. { jump }
  277. if temptovalue then
  278. begin
  279. cg.a_cmp_ref_loc_label(exprasmlist,opsize,hcond,temp1,
  280. t2.location,aktbreaklabel);
  281. end
  282. else
  283. begin
  284. cg.a_cmp_const_loc_label(exprasmlist,opsize,hcond,
  285. aword(tordconstnode(right).value),t2.location,aktbreaklabel);
  286. end;
  287. { according to count direction DEC or INC... }
  288. { must be after the test because of 0 to 255 for bytes !! }
  289. if nf_backward in flags then
  290. hop:=OP_SUB
  291. else
  292. hop:=OP_ADD;
  293. cg.a_op_const_loc(exprasmlist,hop,opsize,1,t2.location);
  294. cg.a_jmp_cond(exprasmlist,OC_None,l3);
  295. if temptovalue then
  296. ungetiftemp(temp1);
  297. { this is the break label: }
  298. cg.a_label(exprasmlist,aktbreaklabel);
  299. aktcontinuelabel:=oldclabel;
  300. aktbreaklabel:=oldblabel;
  301. { a break/continue in a for block can't be seen outside }
  302. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  303. end;
  304. {*****************************************************************************
  305. SecondExitN
  306. *****************************************************************************}
  307. procedure tcgexitnode.pass_2;
  308. var
  309. {op : tasmop;
  310. s : topsize;}
  311. otlabel,oflabel : tasmlabel;
  312. r : treference;
  313. is_mem,
  314. allocated_acc,
  315. allocated_acchigh: boolean;
  316. procedure cleanleft;
  317. begin
  318. if is_mem then
  319. begin
  320. del_reference(left.location.reference);
  321. ungetiftemp(left.location.reference);
  322. end
  323. else
  324. begin
  325. ungetregister(left.location.register);
  326. if left.location.registerhigh <> R_NO then
  327. ungetregister(left.location.registerhigh);
  328. end;
  329. end;
  330. label
  331. do_jmp;
  332. begin
  333. load_all_regvars(exprasmlist);
  334. include(flowcontrol,fc_exit);
  335. if assigned(left) then
  336. if left.nodetype=assignn then
  337. begin
  338. { just do a normal assignment followed by exit }
  339. secondpass(left);
  340. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexitlabel);
  341. end
  342. else
  343. begin
  344. allocated_acc := false;
  345. allocated_acchigh := false;
  346. otlabel:=truelabel;
  347. oflabel:=falselabel;
  348. getlabel(truelabel);
  349. getlabel(falselabel);
  350. secondpass(left);
  351. case left.location.loc of
  352. LOC_FPU : goto do_jmp;
  353. LOC_MEM,
  354. LOC_REFERENCE : is_mem:=true;
  355. LOC_CREGISTER,
  356. LOC_REGISTER : is_mem:=false;
  357. LOC_FLAGS : begin
  358. cg.a_reg_alloc(exprasmlist,accumulator);
  359. allocated_acc := true;
  360. cg.g_flags2reg(exprasmlist,left.location.resflags,accumulator);
  361. goto do_jmp;
  362. end;
  363. LOC_JUMP : begin
  364. exprasmlist.concat(tairegalloc.alloc(accumulator));
  365. allocated_acc := true;
  366. cg.a_label(exprasmlist,truelabel);
  367. cg.a_load_const_reg(exprasmlist,OS_8,1,
  368. makereg8(accumulator));
  369. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexit2label);
  370. cg.a_label(exprasmlist,falselabel);
  371. cg.a_load_const_reg(exprasmlist,OS_8,0,
  372. makereg8(accumulator));
  373. goto do_jmp;
  374. end;
  375. else
  376. internalerror(2001);
  377. end;
  378. case aktprocsym.definition.rettype.def.deftype of
  379. pointerdef,
  380. procvardef : begin
  381. cleanleft;
  382. cg.a_reg_alloc(exprasmlist,accumulator);
  383. allocated_acc := true;
  384. if is_mem then
  385. cg.a_load_ref_reg(exprasmlist,OS_ADDR,
  386. left.location.reference,accumulator)
  387. else
  388. cg.a_load_reg_reg(exprasmlist,OS_ADDR,
  389. left.location.register,accumulator);
  390. end;
  391. floatdef : begin
  392. cleanleft;
  393. if is_mem then
  394. floatload(tfloatdef(aktprocsym.definition.rettype.def).typ,left.location.reference);
  395. end;
  396. { orddef,
  397. enumdef : }
  398. else
  399. { it can be anything shorter than 4 bytes PM
  400. this caused form bug 711 }
  401. begin
  402. cleanleft;
  403. cg.a_reg_alloc(exprasmlist,accumulator);
  404. allocated_acc := true;
  405. case aktprocsym.definition.rettype.def.size of
  406. { it can be a qword/int64 too ... }
  407. 8 :
  408. if is_mem then
  409. begin
  410. cg.a_load_ref_reg(exprasmlist,OS_32,
  411. left.location.reference,accumulator);
  412. r:=left.location.reference;
  413. inc(r.offset,4);
  414. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  415. allocated_acchigh := true;
  416. cg.a_load_ref_reg(exprasmlist,OS_32,r,accumulatorhigh);
  417. end
  418. else
  419. begin
  420. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerlow,accumulator);
  421. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  422. allocated_acchigh := true;
  423. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerhigh,accumulatorhigh);
  424. end;
  425. { if its 3 bytes only we can still
  426. copy one of garbage ! PM }
  427. 4,3 :
  428. cg.a_load_loc_reg(exprasmlist,OS_32,left.location,
  429. accumulator);
  430. 2 :
  431. cg.a_load_loc_reg(exprasmlist,OS_16,left.location,
  432. makereg16(accumulator));
  433. 1 :
  434. cg.a_load_loc_reg(exprasmlist,OS_8,left.location,
  435. makereg8(accumulator));
  436. else internalerror(605001);
  437. end;
  438. end;
  439. end;
  440. do_jmp:
  441. truelabel:=otlabel;
  442. falselabel:=oflabel;
  443. cg.a_jmp_cond(exprasmlist,OC_None,aktexit2label);
  444. if allocated_acc then
  445. cg.a_reg_dealloc(exprasmlist,accumulator);
  446. if allocated_acchigh then
  447. cg.a_reg_dealloc(exprasmlist,accumulator);
  448. end
  449. else
  450. cg.a_jmp_cond(exprasmlist,OC_None,aktexitlabel);
  451. end;
  452. {*****************************************************************************
  453. SecondBreakN
  454. *****************************************************************************}
  455. procedure tcgbreaknode.pass_2;
  456. begin
  457. include(flowcontrol,fc_break);
  458. if aktbreaklabel<>nil then
  459. begin
  460. load_all_regvars(exprasmlist);
  461. cg.a_jmp_cond(exprasmlist,OC_None,aktbreaklabel)
  462. end
  463. else
  464. CGMessage(cg_e_break_not_allowed);
  465. end;
  466. {*****************************************************************************
  467. SecondContinueN
  468. *****************************************************************************}
  469. procedure tcgcontinuenode.pass_2;
  470. begin
  471. include(flowcontrol,fc_continue);
  472. if aktcontinuelabel<>nil then
  473. begin
  474. load_all_regvars(exprasmlist);
  475. cg.a_jmp_cond(exprasmlist,OC_None,aktcontinuelabel)
  476. end
  477. else
  478. CGMessage(cg_e_continue_not_allowed);
  479. end;
  480. {*****************************************************************************
  481. SecondGoto
  482. *****************************************************************************}
  483. procedure tcggotonode.pass_2;
  484. begin
  485. load_all_regvars(exprasmlist);
  486. cg.a_jmp_cond(exprasmlist,OC_None,labelnr)
  487. end;
  488. {*****************************************************************************
  489. SecondLabel
  490. *****************************************************************************}
  491. procedure tcglabelnode.pass_2;
  492. begin
  493. load_all_regvars(exprasmlist);
  494. cg.a_label(exprasmlist,labelnr);
  495. cleartempgen;
  496. secondpass(left);
  497. end;
  498. begin
  499. cwhilerepeatnode:=tcgwhilerepeatnode;
  500. cifnode:=tcgifnode;
  501. cfornode:=tcgfornode;
  502. cexitnode:=tcgexitnode;
  503. cbreaknode:=tcgbreaknode;
  504. ccontinuenode:=tcgcontinuenode;
  505. cgotonode:=tcggotonode;
  506. clabelnode:=tcglabelnode;
  507. end.
  508. {
  509. $Log$
  510. Revision 1.3 2001-10-04 14:33:28 jonas
  511. * fixed range check errors
  512. Revision 1.2 2001/09/30 16:19:58 jonas
  513. - removed unused units
  514. Revision 1.1 2001/09/28 20:39:33 jonas
  515. * changed all flow control structures (except for exception handling
  516. related things) to processor independent code (in new ncgflw unit)
  517. + generic cgobj unit which contains lots of code generator helpers with
  518. global "cg" class instance variable
  519. + cgcpu unit for i386 (implements processor specific routines of the above
  520. unit)
  521. * updated cgbase and cpubase for the new code generator units
  522. * include ncgflw unit in cpunode unit
  523. Revision 1.4 2001/09/09 17:10:25 jonas
  524. * some more things implemented
  525. Revision 1.3 2001/09/06 15:25:55 jonas
  526. * changed type of tcg from object to class -> abstract methods are now
  527. a lot cleaner :)
  528. + more updates: load_*_loc methods, op_*_* methods, g_flags2reg method
  529. (if possible with geenric implementation and necessary ppc
  530. implementations)
  531. * worked a bit further on cgflw, now working on exitnode
  532. Revision 1.2 2001/09/05 20:21:03 jonas
  533. * new cgflow based on n386flw with all nodes until forn "translated"
  534. + a_cmp_*_loc_label methods for tcg
  535. + base implementatino for a_cmp_ref_*_label methods
  536. * small bugfixes to powerpc cg
  537. }