ncgflw.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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,globtype,globals,systems,
  52. symconst,symdef,symsym,aasm,types,
  53. cgbase,temp_gen,pass_2,
  54. cpubase,cpuasm,
  55. pass_1,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. tordconstnode(right).value,t2.location,aktbreaklabel);
  248. end;
  249. end;
  250. { align loop target }
  251. exprasmList.concat(Tai_align.Create(aktalignment.loopalign));
  252. cg.a_label(exprasmlist,l3);
  253. { help register must not be in instruction block }
  254. cleartempgen;
  255. if assigned(t1) then
  256. begin
  257. secondpass(t1);
  258. load_all_regvars(exprasmlist);
  259. end;
  260. cg.a_label(exprasmlist,aktcontinuelabel);
  261. { makes no problems there }
  262. cleartempgen;
  263. if nf_backward in flags then
  264. if count_var_is_signed then
  265. hcond:=OC_LTE
  266. else
  267. hcond:=OC_BE
  268. else
  269. if count_var_is_signed then
  270. hcond:=OC_GTE
  271. else
  272. hcond:=OC_AE;
  273. load_all_regvars(exprasmlist);
  274. { produce comparison and the corresponding }
  275. { jump }
  276. if temptovalue then
  277. begin
  278. cg.a_cmp_ref_loc_label(exprasmlist,opsize,hcond,temp1,
  279. t2.location,aktbreaklabel);
  280. end
  281. else
  282. begin
  283. cg.a_cmp_const_loc_label(exprasmlist,opsize,hcond,
  284. tordconstnode(right).value,t2.location,aktbreaklabel);
  285. end;
  286. { according to count direction DEC or INC... }
  287. { must be after the test because of 0 to 255 for bytes !! }
  288. if nf_backward in flags then
  289. hop:=OP_SUB
  290. else
  291. hop:=OP_ADD;
  292. cg.a_op_const_loc(exprasmlist,hop,opsize,1,t2.location);
  293. cg.a_jmp_cond(exprasmlist,OC_None,l3);
  294. if temptovalue then
  295. ungetiftemp(temp1);
  296. { this is the break label: }
  297. cg.a_label(exprasmlist,aktbreaklabel);
  298. aktcontinuelabel:=oldclabel;
  299. aktbreaklabel:=oldblabel;
  300. { a break/continue in a for block can't be seen outside }
  301. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  302. end;
  303. {*****************************************************************************
  304. SecondExitN
  305. *****************************************************************************}
  306. procedure tcgexitnode.pass_2;
  307. var
  308. {op : tasmop;
  309. s : topsize;}
  310. otlabel,oflabel : tasmlabel;
  311. r : treference;
  312. is_mem,
  313. allocated_acc,
  314. allocated_acchigh: boolean;
  315. procedure cleanleft;
  316. begin
  317. if is_mem then
  318. begin
  319. del_reference(left.location.reference);
  320. ungetiftemp(left.location.reference);
  321. end
  322. else
  323. begin
  324. ungetregister(left.location.register);
  325. if left.location.registerhigh <> R_NO then
  326. ungetregister(left.location.registerhigh);
  327. end;
  328. end;
  329. label
  330. do_jmp;
  331. begin
  332. load_all_regvars(exprasmlist);
  333. include(flowcontrol,fc_exit);
  334. if assigned(left) then
  335. if left.nodetype=assignn then
  336. begin
  337. { just do a normal assignment followed by exit }
  338. secondpass(left);
  339. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexitlabel);
  340. end
  341. else
  342. begin
  343. allocated_acc := false;
  344. allocated_acchigh := false;
  345. otlabel:=truelabel;
  346. oflabel:=falselabel;
  347. getlabel(truelabel);
  348. getlabel(falselabel);
  349. secondpass(left);
  350. case left.location.loc of
  351. LOC_FPU : goto do_jmp;
  352. LOC_MEM,
  353. LOC_REFERENCE : is_mem:=true;
  354. LOC_CREGISTER,
  355. LOC_REGISTER : is_mem:=false;
  356. LOC_FLAGS : begin
  357. cg.a_reg_alloc(exprasmlist,accumulator);
  358. allocated_acc := true;
  359. cg.g_flags2reg(exprasmlist,left.location.resflags,accumulator);
  360. goto do_jmp;
  361. end;
  362. LOC_JUMP : begin
  363. exprasmlist.concat(tairegalloc.alloc(accumulator));
  364. allocated_acc := true;
  365. cg.a_label(exprasmlist,truelabel);
  366. cg.a_load_const_reg(exprasmlist,OS_8,1,
  367. makereg8(accumulator));
  368. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexit2label);
  369. cg.a_label(exprasmlist,falselabel);
  370. cg.a_load_const_reg(exprasmlist,OS_8,0,
  371. makereg8(accumulator));
  372. goto do_jmp;
  373. end;
  374. else
  375. internalerror(2001);
  376. end;
  377. case aktprocsym.definition.rettype.def.deftype of
  378. pointerdef,
  379. procvardef : begin
  380. cleanleft;
  381. cg.a_reg_alloc(exprasmlist,accumulator);
  382. allocated_acc := true;
  383. if is_mem then
  384. cg.a_load_ref_reg(exprasmlist,OS_ADDR,
  385. left.location.reference,accumulator)
  386. else
  387. cg.a_load_reg_reg(exprasmlist,OS_ADDR,
  388. left.location.register,accumulator);
  389. end;
  390. floatdef : begin
  391. cleanleft;
  392. if is_mem then
  393. floatload(tfloatdef(aktprocsym.definition.rettype.def).typ,left.location.reference);
  394. end;
  395. { orddef,
  396. enumdef : }
  397. else
  398. { it can be anything shorter than 4 bytes PM
  399. this caused form bug 711 }
  400. begin
  401. cleanleft;
  402. cg.a_reg_alloc(exprasmlist,accumulator);
  403. allocated_acc := true;
  404. case aktprocsym.definition.rettype.def.size of
  405. { it can be a qword/int64 too ... }
  406. 8 :
  407. if is_mem then
  408. begin
  409. cg.a_load_ref_reg(exprasmlist,OS_32,
  410. left.location.reference,accumulator);
  411. r:=left.location.reference;
  412. inc(r.offset,4);
  413. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  414. allocated_acchigh := true;
  415. cg.a_load_ref_reg(exprasmlist,OS_32,r,accumulatorhigh);
  416. end
  417. else
  418. begin
  419. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerlow,accumulator);
  420. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  421. allocated_acchigh := true;
  422. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerhigh,accumulatorhigh);
  423. end;
  424. { if its 3 bytes only we can still
  425. copy one of garbage ! PM }
  426. 4,3 :
  427. cg.a_load_loc_reg(exprasmlist,OS_32,left.location,
  428. accumulator);
  429. 2 :
  430. cg.a_load_loc_reg(exprasmlist,OS_16,left.location,
  431. makereg16(accumulator));
  432. 1 :
  433. cg.a_load_loc_reg(exprasmlist,OS_8,left.location,
  434. makereg8(accumulator));
  435. else internalerror(605001);
  436. end;
  437. end;
  438. end;
  439. do_jmp:
  440. truelabel:=otlabel;
  441. falselabel:=oflabel;
  442. cg.a_jmp_cond(exprasmlist,OC_None,aktexit2label);
  443. if allocated_acc then
  444. cg.a_reg_dealloc(exprasmlist,accumulator);
  445. if allocated_acchigh then
  446. cg.a_reg_dealloc(exprasmlist,accumulator);
  447. end
  448. else
  449. cg.a_jmp_cond(exprasmlist,OC_None,aktexitlabel);
  450. end;
  451. {*****************************************************************************
  452. SecondBreakN
  453. *****************************************************************************}
  454. procedure tcgbreaknode.pass_2;
  455. begin
  456. include(flowcontrol,fc_break);
  457. if aktbreaklabel<>nil then
  458. begin
  459. load_all_regvars(exprasmlist);
  460. cg.a_jmp_cond(exprasmlist,OC_None,aktbreaklabel)
  461. end
  462. else
  463. CGMessage(cg_e_break_not_allowed);
  464. end;
  465. {*****************************************************************************
  466. SecondContinueN
  467. *****************************************************************************}
  468. procedure tcgcontinuenode.pass_2;
  469. begin
  470. include(flowcontrol,fc_continue);
  471. if aktcontinuelabel<>nil then
  472. begin
  473. load_all_regvars(exprasmlist);
  474. cg.a_jmp_cond(exprasmlist,OC_None,aktcontinuelabel)
  475. end
  476. else
  477. CGMessage(cg_e_continue_not_allowed);
  478. end;
  479. {*****************************************************************************
  480. SecondGoto
  481. *****************************************************************************}
  482. procedure tcggotonode.pass_2;
  483. begin
  484. load_all_regvars(exprasmlist);
  485. cg.a_jmp_cond(exprasmlist,OC_None,labelnr)
  486. end;
  487. {*****************************************************************************
  488. SecondLabel
  489. *****************************************************************************}
  490. procedure tcglabelnode.pass_2;
  491. begin
  492. load_all_regvars(exprasmlist);
  493. cg.a_label(exprasmlist,labelnr);
  494. cleartempgen;
  495. secondpass(left);
  496. end;
  497. begin
  498. cwhilerepeatnode:=tcgwhilerepeatnode;
  499. cifnode:=tcgifnode;
  500. cfornode:=tcgfornode;
  501. cexitnode:=tcgexitnode;
  502. cbreaknode:=tcgbreaknode;
  503. ccontinuenode:=tcgcontinuenode;
  504. cgotonode:=tcggotonode;
  505. clabelnode:=tcglabelnode;
  506. end.
  507. {
  508. $Log$
  509. Revision 1.1 2001-09-28 20:39:33 jonas
  510. * changed all flow control structures (except for exception handling
  511. related things) to processor independent code (in new ncgflw unit)
  512. + generic cgobj unit which contains lots of code generator helpers with
  513. global "cg" class instance variable
  514. + cgcpu unit for i386 (implements processor specific routines of the above
  515. unit)
  516. * updated cgbase and cpubase for the new code generator units
  517. * include ncgflw unit in cpunode unit
  518. Revision 1.4 2001/09/09 17:10:25 jonas
  519. * some more things implemented
  520. Revision 1.3 2001/09/06 15:25:55 jonas
  521. * changed type of tcg from object to class -> abstract methods are now
  522. a lot cleaner :)
  523. + more updates: load_*_loc methods, op_*_* methods, g_flags2reg method
  524. (if possible with geenric implementation and necessary ppc
  525. implementations)
  526. * worked a bit further on cgflw, now working on exitnode
  527. Revision 1.2 2001/09/05 20:21:03 jonas
  528. * new cgflow based on n386flw with all nodes until forn "translated"
  529. + a_cmp_*_loc_label methods for tcg
  530. + base implementatino for a_cmp_ref_*_label methods
  531. * small bugfixes to powerpc cg
  532. }