ncgflw.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  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,globtype,
  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. maketojumpbool(left,lr_load_regvars);
  107. cg.a_label(exprasmlist,lbreak);
  108. truelabel:=otlabel;
  109. falselabel:=oflabel;
  110. aktcontinuelabel:=oldclabel;
  111. aktbreaklabel:=oldblabel;
  112. { a break/continue in a while/repeat block can't be seen outside }
  113. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  114. end;
  115. {*****************************************************************************
  116. tcgIFNODE
  117. *****************************************************************************}
  118. procedure tcgifnode.pass_2;
  119. var
  120. hl,otlabel,oflabel : tasmlabel;
  121. org_regvar_loaded,
  122. then_regvar_loaded,
  123. else_regvar_loaded : regvar_booleanarray;
  124. org_list,
  125. then_list,
  126. else_list : taasmoutput;
  127. regcounter: tregister;
  128. begin
  129. otlabel:=truelabel;
  130. oflabel:=falselabel;
  131. getlabel(truelabel);
  132. getlabel(falselabel);
  133. cleartempgen;
  134. secondpass(left);
  135. { save regvars loaded in the beginning so that we can restore them }
  136. { when processing the else-block }
  137. if cs_regalloc in aktglobalswitches then
  138. begin
  139. org_list := exprasmlist;
  140. exprasmlist := taasmoutput.create;
  141. end;
  142. maketojumpbool(left,lr_dont_load_regvars);
  143. if cs_regalloc in aktglobalswitches then
  144. org_regvar_loaded := regvar_loaded;
  145. if assigned(right) then
  146. begin
  147. cg.a_label(exprasmlist,truelabel);
  148. cleartempgen;
  149. secondpass(right);
  150. end;
  151. { save current asmlist (previous instructions + then-block) and }
  152. { loaded regvar state and create new clean ones }
  153. if cs_regalloc in aktglobalswitches then
  154. begin
  155. then_regvar_loaded := regvar_loaded;
  156. regvar_loaded := org_regvar_loaded;
  157. then_list := exprasmlist;
  158. exprasmlist := taasmoutput.create;
  159. end;
  160. if assigned(t1) then
  161. begin
  162. if assigned(right) then
  163. begin
  164. getlabel(hl);
  165. { do go back to if line !! }
  166. if not(cs_regalloc in aktglobalswitches) then
  167. aktfilepos:=exprasmList.getlasttaifilepos^
  168. else
  169. aktfilepos:=then_list.getlasttaifilepos^;
  170. cg.a_jmp_cond(exprasmlist,OC_None,hl);
  171. end;
  172. cg.a_label(exprasmlist,falselabel);
  173. cleartempgen;
  174. secondpass(t1);
  175. { save current asmlist (previous instructions + else-block) }
  176. { and loaded regvar state and create a new clean list }
  177. if cs_regalloc in aktglobalswitches then
  178. begin
  179. else_regvar_loaded := regvar_loaded;
  180. else_list := exprasmlist;
  181. exprasmlist := taasmoutput.create;
  182. end;
  183. if assigned(right) then
  184. cg.a_label(exprasmlist,hl);
  185. end
  186. else
  187. begin
  188. if cs_regalloc in aktglobalswitches then
  189. begin
  190. else_regvar_loaded := regvar_loaded;
  191. else_list := exprasmlist;
  192. exprasmlist := taasmoutput.create;
  193. end;
  194. cg.a_label(exprasmlist,falselabel);
  195. end;
  196. if not(assigned(right)) then
  197. begin
  198. cg.a_label(exprasmlist,truelabel);
  199. end;
  200. if cs_regalloc in aktglobalswitches then
  201. begin
  202. { add loads of regvars at the end of the then- and else-blocks }
  203. { so that at the end of both blocks the same regvars are loaded }
  204. { no else block? }
  205. if not assigned(t1) then
  206. sync_regvars(org_list,then_list,org_regvar_loaded,
  207. then_regvar_loaded)
  208. { no then block? }
  209. else if not assigned(right) then
  210. sync_regvars(org_list,else_list,org_regvar_loaded,
  211. else_regvar_loaded)
  212. { both else and then blocks }
  213. else
  214. sync_regvars(then_list,else_list,then_regvar_loaded,
  215. else_regvar_loaded);
  216. { add all lists together }
  217. org_list.concatlist(then_list);
  218. then_list.free;
  219. org_list.concatlist(else_list);
  220. else_list.free;
  221. org_list.concatlist(exprasmlist);
  222. exprasmlist.free;
  223. exprasmlist := org_list;
  224. end;
  225. truelabel:=otlabel;
  226. falselabel:=oflabel;
  227. end;
  228. {*****************************************************************************
  229. SecondFor
  230. *****************************************************************************}
  231. procedure tcgfornode.pass_2;
  232. var
  233. l3,oldclabel,oldblabel : tasmlabel;
  234. omitfirstcomp,temptovalue : boolean;
  235. hs : byte;
  236. temp1 : treference;
  237. hop : topcg;
  238. hcond : topcmp;
  239. opsize : tcgsize;
  240. count_var_is_signed : boolean;
  241. begin
  242. oldclabel:=aktcontinuelabel;
  243. oldblabel:=aktbreaklabel;
  244. getlabel(aktcontinuelabel);
  245. getlabel(aktbreaklabel);
  246. getlabel(l3);
  247. { could we spare the first comparison ? }
  248. omitfirstcomp:=false;
  249. if right.nodetype=ordconstn then
  250. if tassignmentnode(left).right.nodetype=ordconstn then
  251. omitfirstcomp:=((nf_backward in flags) and
  252. (tordconstnode(tassignmentnode(left).right).value>=tordconstnode(right).value))
  253. or (not(nf_backward in flags) and
  254. (tordconstnode(tassignmentnode(left).right).value<=tordconstnode(right).value));
  255. { only calculate reference }
  256. cleartempgen;
  257. secondpass(t2);
  258. hs := t2.resulttype.def.size;
  259. opsize := def_cgsize(t2.resulttype.def);
  260. { first set the to value
  261. because the count var can be in the expression !! }
  262. cleartempgen;
  263. secondpass(right);
  264. { calculate pointer value and check if changeable and if so }
  265. { load into temporary variable }
  266. if right.nodetype<>ordconstn then
  267. begin
  268. temp1.symbol:=nil;
  269. gettempofsizereference(hs,temp1);
  270. temptovalue:=true;
  271. if (right.location.loc=LOC_REGISTER) or
  272. (right.location.loc=LOC_CREGISTER) then
  273. begin
  274. cg.a_load_reg_ref(exprasmlist,opsize,
  275. right.location.register,temp1);
  276. ungetregister(right.location.register);
  277. end
  278. else
  279. cg.g_concatcopy(exprasmlist,right.location.reference,temp1,
  280. hs,true,false);
  281. end
  282. else
  283. temptovalue:=false;
  284. { produce start assignment }
  285. cleartempgen;
  286. secondpass(left);
  287. count_var_is_signed:=is_signed(torddef(t2.resulttype.def));
  288. if nf_backward in flags then
  289. if count_var_is_signed then
  290. hcond:=OC_LT
  291. else
  292. hcond:=OC_B
  293. else
  294. if count_var_is_signed then
  295. hcond:=OC_GT
  296. else
  297. hcond:=OC_A;
  298. load_all_regvars(exprasmlist);
  299. if temptovalue then
  300. begin
  301. cg.a_cmp_ref_loc_label(exprasmlist,opsize,hcond,
  302. temp1,t2.location,aktbreaklabel);
  303. end
  304. else
  305. begin
  306. if not(omitfirstcomp) then
  307. begin
  308. cg.a_cmp_const_loc_label(exprasmlist,opsize,hcond,
  309. aword(tordconstnode(right).value),
  310. t2.location,aktbreaklabel);
  311. end;
  312. end;
  313. { align loop target }
  314. exprasmList.concat(Tai_align.Create(aktalignment.loopalign));
  315. cg.a_label(exprasmlist,l3);
  316. { help register must not be in instruction block }
  317. cleartempgen;
  318. if assigned(t1) then
  319. begin
  320. secondpass(t1);
  321. load_all_regvars(exprasmlist);
  322. end;
  323. cg.a_label(exprasmlist,aktcontinuelabel);
  324. { makes no problems there }
  325. cleartempgen;
  326. if nf_backward in flags then
  327. if count_var_is_signed then
  328. hcond:=OC_LTE
  329. else
  330. hcond:=OC_BE
  331. else
  332. if count_var_is_signed then
  333. hcond:=OC_GTE
  334. else
  335. hcond:=OC_AE;
  336. load_all_regvars(exprasmlist);
  337. { produce comparison and the corresponding }
  338. { jump }
  339. if temptovalue then
  340. begin
  341. cg.a_cmp_ref_loc_label(exprasmlist,opsize,hcond,temp1,
  342. t2.location,aktbreaklabel);
  343. end
  344. else
  345. begin
  346. cg.a_cmp_const_loc_label(exprasmlist,opsize,hcond,
  347. aword(tordconstnode(right).value),t2.location,aktbreaklabel);
  348. end;
  349. { according to count direction DEC or INC... }
  350. { must be after the test because of 0 to 255 for bytes !! }
  351. if nf_backward in flags then
  352. hop:=OP_SUB
  353. else
  354. hop:=OP_ADD;
  355. cg.a_op_const_loc(exprasmlist,hop,opsize,1,t2.location);
  356. cg.a_jmp_cond(exprasmlist,OC_None,l3);
  357. if temptovalue then
  358. ungetiftemp(temp1);
  359. { this is the break label: }
  360. cg.a_label(exprasmlist,aktbreaklabel);
  361. aktcontinuelabel:=oldclabel;
  362. aktbreaklabel:=oldblabel;
  363. { a break/continue in a for block can't be seen outside }
  364. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  365. end;
  366. {*****************************************************************************
  367. SecondExitN
  368. *****************************************************************************}
  369. procedure tcgexitnode.pass_2;
  370. var
  371. {op : tasmop;
  372. s : topsize;}
  373. otlabel,oflabel : tasmlabel;
  374. r : treference;
  375. is_mem,
  376. allocated_acc,
  377. allocated_acchigh: boolean;
  378. procedure cleanleft;
  379. begin
  380. if is_mem then
  381. begin
  382. del_reference(left.location.reference);
  383. ungetiftemp(left.location.reference);
  384. end
  385. else
  386. begin
  387. ungetregister(left.location.register);
  388. if left.location.registerhigh <> R_NO then
  389. ungetregister(left.location.registerhigh);
  390. end;
  391. end;
  392. label
  393. do_jmp;
  394. begin
  395. { load_all_regvars(exprasmlist); }
  396. include(flowcontrol,fc_exit);
  397. if assigned(left) then
  398. if left.nodetype=assignn then
  399. begin
  400. { just do a normal assignment followed by exit }
  401. secondpass(left);
  402. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexitlabel);
  403. end
  404. else
  405. begin
  406. allocated_acc := false;
  407. allocated_acchigh := false;
  408. otlabel:=truelabel;
  409. oflabel:=falselabel;
  410. getlabel(truelabel);
  411. getlabel(falselabel);
  412. secondpass(left);
  413. case left.location.loc of
  414. LOC_FPU : goto do_jmp;
  415. LOC_MEM,
  416. LOC_REFERENCE : is_mem:=true;
  417. LOC_CREGISTER,
  418. LOC_REGISTER : is_mem:=false;
  419. LOC_FLAGS : begin
  420. cg.a_reg_alloc(exprasmlist,accumulator);
  421. allocated_acc := true;
  422. cg.g_flags2reg(exprasmlist,left.location.resflags,accumulator);
  423. goto do_jmp;
  424. end;
  425. LOC_JUMP : begin
  426. exprasmlist.concat(tairegalloc.alloc(accumulator));
  427. allocated_acc := true;
  428. cg.a_label(exprasmlist,truelabel);
  429. cg.a_load_const_reg(exprasmlist,OS_8,1,
  430. makereg8(accumulator));
  431. cg.a_jmp_cond(exprasmlist,OC_NONE,aktexit2label);
  432. cg.a_label(exprasmlist,falselabel);
  433. cg.a_load_const_reg(exprasmlist,OS_8,0,
  434. makereg8(accumulator));
  435. goto do_jmp;
  436. end;
  437. else
  438. internalerror(2001);
  439. end;
  440. case aktprocdef.rettype.def.deftype of
  441. pointerdef,
  442. procvardef : begin
  443. cleanleft;
  444. cg.a_reg_alloc(exprasmlist,accumulator);
  445. allocated_acc := true;
  446. if is_mem then
  447. cg.a_load_ref_reg(exprasmlist,OS_ADDR,
  448. left.location.reference,accumulator)
  449. else
  450. cg.a_load_reg_reg(exprasmlist,OS_ADDR,
  451. left.location.register,accumulator);
  452. end;
  453. floatdef : begin
  454. cleanleft;
  455. if is_mem then
  456. floatload(tfloatdef(aktprocdef.rettype.def).typ,left.location.reference);
  457. end;
  458. { orddef,
  459. enumdef : }
  460. else
  461. { it can be anything shorter than 4 bytes PM
  462. this caused form bug 711 }
  463. begin
  464. cleanleft;
  465. cg.a_reg_alloc(exprasmlist,accumulator);
  466. allocated_acc := true;
  467. case aktprocdef.rettype.def.size of
  468. { it can be a qword/int64 too ... }
  469. 8 :
  470. if is_mem then
  471. begin
  472. cg.a_load_ref_reg(exprasmlist,OS_32,
  473. left.location.reference,accumulator);
  474. r:=left.location.reference;
  475. inc(r.offset,4);
  476. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  477. allocated_acchigh := true;
  478. cg.a_load_ref_reg(exprasmlist,OS_32,r,accumulatorhigh);
  479. end
  480. else
  481. begin
  482. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerlow,accumulator);
  483. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  484. allocated_acchigh := true;
  485. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerhigh,accumulatorhigh);
  486. end;
  487. { if its 3 bytes only we can still
  488. copy one of garbage ! PM }
  489. 4,3 :
  490. cg.a_load_loc_reg(exprasmlist,OS_32,left.location,
  491. accumulator);
  492. 2 :
  493. cg.a_load_loc_reg(exprasmlist,OS_16,left.location,
  494. makereg16(accumulator));
  495. 1 :
  496. cg.a_load_loc_reg(exprasmlist,OS_8,left.location,
  497. makereg8(accumulator));
  498. else internalerror(605001);
  499. end;
  500. end;
  501. end;
  502. do_jmp:
  503. truelabel:=otlabel;
  504. falselabel:=oflabel;
  505. cg.a_jmp_cond(exprasmlist,OC_None,aktexit2label);
  506. if allocated_acc then
  507. cg.a_reg_dealloc(exprasmlist,accumulator);
  508. if allocated_acchigh then
  509. cg.a_reg_dealloc(exprasmlist,accumulator);
  510. end
  511. else
  512. cg.a_jmp_cond(exprasmlist,OC_None,aktexitlabel);
  513. end;
  514. {*****************************************************************************
  515. SecondBreakN
  516. *****************************************************************************}
  517. procedure tcgbreaknode.pass_2;
  518. begin
  519. include(flowcontrol,fc_break);
  520. if aktbreaklabel<>nil then
  521. begin
  522. load_all_regvars(exprasmlist);
  523. cg.a_jmp_cond(exprasmlist,OC_None,aktbreaklabel)
  524. end
  525. else
  526. CGMessage(cg_e_break_not_allowed);
  527. end;
  528. {*****************************************************************************
  529. SecondContinueN
  530. *****************************************************************************}
  531. procedure tcgcontinuenode.pass_2;
  532. begin
  533. include(flowcontrol,fc_continue);
  534. if aktcontinuelabel<>nil then
  535. begin
  536. load_all_regvars(exprasmlist);
  537. cg.a_jmp_cond(exprasmlist,OC_None,aktcontinuelabel)
  538. end
  539. else
  540. CGMessage(cg_e_continue_not_allowed);
  541. end;
  542. {*****************************************************************************
  543. SecondGoto
  544. *****************************************************************************}
  545. procedure tcggotonode.pass_2;
  546. begin
  547. load_all_regvars(exprasmlist);
  548. cg.a_jmp_cond(exprasmlist,OC_None,labelnr)
  549. end;
  550. {*****************************************************************************
  551. SecondLabel
  552. *****************************************************************************}
  553. procedure tcglabelnode.pass_2;
  554. begin
  555. load_all_regvars(exprasmlist);
  556. cg.a_label(exprasmlist,labelnr);
  557. cleartempgen;
  558. secondpass(left);
  559. end;
  560. begin
  561. cwhilerepeatnode:=tcgwhilerepeatnode;
  562. cifnode:=tcgifnode;
  563. cfornode:=tcgfornode;
  564. cexitnode:=tcgexitnode;
  565. cbreaknode:=tcgbreaknode;
  566. ccontinuenode:=tcgcontinuenode;
  567. cgotonode:=tcggotonode;
  568. clabelnode:=tcglabelnode;
  569. end.
  570. {
  571. $Log$
  572. Revision 1.5 2001-12-02 16:19:17 jonas
  573. * less unnecessary regvar loading with if-statements
  574. Revision 1.4 2001/11/02 22:58:01 peter
  575. * procsym definition rewrite
  576. Revision 1.3 2001/10/04 14:33:28 jonas
  577. * fixed range check errors
  578. Revision 1.2 2001/09/30 16:19:58 jonas
  579. - removed unused units
  580. Revision 1.1 2001/09/28 20:39:33 jonas
  581. * changed all flow control structures (except for exception handling
  582. related things) to processor independent code (in new ncgflw unit)
  583. + generic cgobj unit which contains lots of code generator helpers with
  584. global "cg" class instance variable
  585. + cgcpu unit for i386 (implements processor specific routines of the above
  586. unit)
  587. * updated cgbase and cpubase for the new code generator units
  588. * include ncgflw unit in cpunode unit
  589. Revision 1.4 2001/09/09 17:10:25 jonas
  590. * some more things implemented
  591. Revision 1.3 2001/09/06 15:25:55 jonas
  592. * changed type of tcg from object to class -> abstract methods are now
  593. a lot cleaner :)
  594. + more updates: load_*_loc methods, op_*_* methods, g_flags2reg method
  595. (if possible with geenric implementation and necessary ppc
  596. implementations)
  597. * worked a bit further on cgflw, now working on exitnode
  598. Revision 1.2 2001/09/05 20:21:03 jonas
  599. * new cgflow based on n386flw with all nodes until forn "translated"
  600. + a_cmp_*_loc_label methods for tcg
  601. + base implementatino for a_cmp_ref_*_label methods
  602. * small bugfixes to powerpc cg
  603. }