ncpuadd.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. {******************************************************************************
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Code generation for add nodes on the i386
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; IF not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************}
  17. unit ncpuadd;
  18. {$INCLUDE fpcdefs.inc}
  19. interface
  20. uses
  21. node,nadd,cpubase,cginfo;
  22. type
  23. TSparcAddNode=class(TAddNode)
  24. procedure pass_2;override;
  25. private
  26. procedure second_addboolean;
  27. function GetResFlags(unsigned:Boolean):TResFlags;
  28. procedure left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  29. procedure emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  30. procedure emit_op_right_left(op:TAsmOp);
  31. procedure pass_left_and_right;
  32. procedure set_result_location(cmpOp,unsigned:Boolean);
  33. end;
  34. implementation
  35. uses
  36. globtype,systems,
  37. cutils,verbose,globals,
  38. symconst,symdef,SymType,paramgr,
  39. aasmbase,aasmtai,aasmcpu,defutil,htypechk,
  40. cgbase,pass_2,regvars,
  41. cpupara,
  42. ncon,nset,
  43. ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  44. const
  45. opsize_2_cgSize:array[S_B..S_L]of TCgSize=(OS_8,OS_16,OS_32);
  46. procedure TSparcAddNode.second_addboolean;
  47. var
  48. cgop:TOpCg;
  49. cgsize:TCgSize;
  50. cmpop,isjump:boolean;
  51. otl,ofl:tasmlabel;
  52. pushedregs:TMaybeSave;
  53. begin
  54. { calculate the operator which is more difficult }
  55. firstcomplex(self);
  56. cmpop:=false;
  57. if (torddef(left.resulttype.def).typ=bool8bit) or
  58. (torddef(right.resulttype.def).typ=bool8bit)
  59. then
  60. cgsize:=OS_8
  61. else if (torddef(left.resulttype.def).typ=bool16bit) or
  62. (torddef(right.resulttype.def).typ=bool16bit)
  63. then
  64. cgsize:=OS_16
  65. else
  66. cgsize:=OS_32;
  67. if (cs_full_boolean_eval in aktlocalswitches) or
  68. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn])
  69. then
  70. begin
  71. if left.nodetype in [ordconstn,realconstn]
  72. then
  73. swapleftright;
  74. isjump:=(left.location.loc=LOC_JUMP);
  75. if isjump
  76. then
  77. begin
  78. otl:=truelabel;
  79. objectlibrary.getlabel(truelabel);
  80. ofl:=falselabel;
  81. objectlibrary.getlabel(falselabel);
  82. end;
  83. secondpass(left);
  84. if left.location.loc in [LOC_FLAGS,LOC_JUMP]
  85. then
  86. location_force_reg(exprasmlist,left.location,cgsize,false);
  87. if isjump
  88. then
  89. begin
  90. truelabel:=otl;
  91. falselabel:=ofl;
  92. end;
  93. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  94. isjump:=(right.location.loc=LOC_JUMP);
  95. if isjump
  96. then
  97. begin
  98. otl:=truelabel;
  99. objectlibrary.getlabel(truelabel);
  100. ofl:=falselabel;
  101. objectlibrary.getlabel(falselabel);
  102. end;
  103. secondpass(right);
  104. maybe_restore(exprasmlist,left.location,pushedregs);
  105. if right.location.loc in [LOC_FLAGS,LOC_JUMP]
  106. then
  107. location_force_reg(exprasmlist,right.location,cgsize,false);
  108. if isjump
  109. then
  110. begin
  111. truelabel:=otl;
  112. falselabel:=ofl;
  113. end;
  114. cmpop := nodetype in [ltn,lten,gtn,gten,equaln,unequaln];
  115. { set result location }
  116. if not cmpop
  117. then
  118. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  119. else
  120. location_reset(location,LOC_FLAGS,OS_NO);
  121. //load_left_right(cmpop,false);
  122. if (left.location.loc = LOC_CONSTANT)
  123. then
  124. swapleftright;
  125. { compare the }
  126. case nodetype of
  127. ltn,lten,gtn,gten,
  128. equaln,unequaln :
  129. begin
  130. if (right.location.loc <> LOC_CONSTANT)
  131. then
  132. exprasmlist.concat(taicpu.op_reg_reg(A_JMPL,left.location.register,right.location.register))
  133. else
  134. exprasmlist.concat(taicpu.op_reg_const(A_JMPL,left.location.register,longint(right.location.value)));
  135. location.resflags := GetResFlags(true);
  136. end;
  137. else
  138. begin
  139. case nodetype of
  140. xorn :
  141. cgop:=OP_XOR;
  142. orn :
  143. cgop:=OP_OR;
  144. andn :
  145. cgop:=OP_AND;
  146. else
  147. internalerror(200203247);
  148. end;
  149. if right.location.loc <> LOC_CONSTANT
  150. then
  151. cg.a_op_reg_reg_reg(exprasmlist,cgop,OS_INT,left.location.register,right.location.register,location.register)
  152. else
  153. cg.a_op_const_reg_reg(exprasmlist,cgop,OS_INT,right.location.value,left.location.register,location.register);
  154. end;
  155. end;
  156. end
  157. else
  158. begin
  159. // just to make sure we free the right registers
  160. cmpop := true;
  161. case nodetype of
  162. andn,
  163. orn :
  164. begin
  165. location_reset(location,LOC_JUMP,OS_NO);
  166. case nodetype of
  167. andn :
  168. begin
  169. otl:=truelabel;
  170. objectlibrary.getlabel(truelabel);
  171. secondpass(left);
  172. maketojumpbool(exprasmlist,left,lr_load_regvars);
  173. cg.a_label(exprasmlist,truelabel);
  174. truelabel:=otl;
  175. end;
  176. orn :
  177. begin
  178. ofl:=falselabel;
  179. objectlibrary.getlabel(falselabel);
  180. secondpass(left);
  181. maketojumpbool(exprasmlist,left,lr_load_regvars);
  182. cg.a_label(exprasmlist,falselabel);
  183. falselabel:=ofl;
  184. end;
  185. else
  186. CGMessage(type_e_mismatch);
  187. end;
  188. secondpass(right);
  189. maketojumpbool(exprasmlist,right,lr_load_regvars);
  190. end;
  191. end;
  192. end;
  193. // clear_left_right(CmpOp);
  194. end;
  195. function TSparcAddNode.GetResFlags(unsigned:Boolean):TResFlags;
  196. begin
  197. case NodeType of
  198. equaln:
  199. GetResFlags:=F_E;
  200. unequaln:
  201. GetResFlags:=F_NE;
  202. else
  203. if not(unsigned)
  204. then
  205. if nf_swaped IN flags
  206. then
  207. case NodeType of
  208. ltn:
  209. GetResFlags:=F_G;
  210. lten:
  211. GetResFlags:=F_GE;
  212. gtn:
  213. GetResFlags:=F_L;
  214. gten:
  215. GetResFlags:=F_LE;
  216. end
  217. else
  218. case NodeType of
  219. ltn:
  220. GetResFlags:=F_L;
  221. lten:
  222. GetResFlags:=F_LE;
  223. gtn:
  224. GetResFlags:=F_G;
  225. gten:
  226. GetResFlags:=F_GE;
  227. end
  228. else
  229. if nf_swaped IN Flags
  230. then
  231. case NodeType of
  232. ltn:
  233. GetResFlags:=F_A;
  234. lten:
  235. GetResFlags:=F_AE;
  236. gtn:
  237. GetResFlags:=F_B;
  238. gten:
  239. GetResFlags:=F_BE;
  240. end
  241. else
  242. case NodeType of
  243. ltn:
  244. GetResFlags:=F_B;
  245. lten:
  246. GetResFlags:=F_BE;
  247. gtn:
  248. GetResFlags:=F_A;
  249. gten:
  250. GetResFlags:=F_AE;
  251. end;
  252. end;
  253. end;
  254. procedure TSparcAddNode.left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  255. begin
  256. if(left.location.loc=LOC_REGISTER)
  257. then
  258. exit;
  259. {left location is not a register}
  260. if(not NoSwap)and(right.location.loc=LOC_REGISTER)
  261. then{right is register so we can swap the locations}
  262. begin
  263. location_swap(left.location,right.location);
  264. toggleflag(nf_swaped);
  265. end
  266. else
  267. begin
  268. {maybe we can reuse a constant register when the operation is a comparison that
  269. doesn't change the value of the register}
  270. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  271. end;
  272. end;
  273. procedure TSparcAddNode.emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  274. VAR
  275. power:LongInt;
  276. hl4:TAsmLabel;
  277. begin
  278. { at this point, left.location.loc should be LOC_REGISTER }
  279. if right.location.loc=LOC_REGISTER
  280. then
  281. begin
  282. { right.location is a LOC_REGISTER }
  283. { when swapped another result register }
  284. if(nodetype=subn)and(nf_swaped in flags)
  285. then
  286. begin
  287. if extra_not
  288. then
  289. exprasmList.concat(Taicpu.Op_reg(A_NOT,left.location.register));
  290. exprasmList.concat(Taicpu.Op_reg_reg_reg(Op,right.location.register,left.location.register,right.location.register));
  291. { newly swapped also set swapped flag }
  292. location_swap(left.location,right.location);
  293. toggleflag(nf_swaped);
  294. end
  295. else
  296. begin
  297. if extra_not
  298. then
  299. exprasmList.concat(Taicpu.Op_reg(A_NOT,right.location.register));
  300. // emit_reg_reg(op,opsize,right.location.register,left.location.register);
  301. exprasmList.concat(Taicpu.Op_reg_reg_reg(Op,right.location.register,left.location.register,right.location.register));
  302. end;
  303. end
  304. ELSE
  305. begin
  306. { right.location is not a LOC_REGISTER }
  307. IF(nodetype=subn)AND(nf_swaped IN flags)
  308. THEN
  309. begin
  310. IF extra_not
  311. THEN
  312. exprasmList.concat(Taicpu.Op_reg(A_NOT,left.location.register));
  313. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  314. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  315. // emit_reg_reg(op,opsize,left.location.register,R_EDI);
  316. // emit_reg_reg(A_MOV,opsize,R_EDI,left.location.register);
  317. // rg.ungetregisterint(exprasmlist,R_EDI);
  318. end
  319. ELSE
  320. begin
  321. { Optimizations when right.location is a constant value }
  322. IF(op=A_CMP)AND(nodetype IN [equaln,unequaln])AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=0)
  323. THEN
  324. begin
  325. // emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  326. end
  327. ELSE IF(op=A_ADD)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  328. THEN
  329. with ExprAsmList,left.location do
  330. begin
  331. concat(TAiCpu.op_reg_const_reg(A_ADD,register,1,register));
  332. end
  333. ELSE IF(op=A_SUB)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  334. THEN
  335. begin
  336. exprasmList.concat(Taicpu.Op_reg(A_DEC,left.location.register));
  337. end
  338. ELSE IF(op=A_SMUL)AND(right.location.loc=LOC_CONSTANT)AND(ispowerof2(right.location.value,power))AND NOT(cs_check_overflow in aktlocalswitches)
  339. THEN
  340. begin
  341. exprasmList.concat(Taicpu.Op_const_reg(A_SLL,power,left.location.register));
  342. end
  343. ELSE
  344. begin
  345. IF extra_not
  346. THEN
  347. begin
  348. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  349. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  350. // emit_reg(A_NOT,S_L,R_EDI);
  351. // emit_reg_reg(A_AND,S_L,R_EDI,left.location.register);
  352. // rg.ungetregisterint(exprasmlist,R_EDI);
  353. end
  354. ELSE
  355. begin
  356. emit_op_right_left(op);
  357. end;
  358. end;
  359. end;
  360. end;
  361. { only in case of overflow operations }
  362. { produce overflow code }
  363. { we must put it here directly, because sign of operation }
  364. { is in unsigned VAR!! }
  365. IF mboverflow
  366. THEN
  367. begin
  368. IF cs_check_overflow IN aktlocalswitches
  369. THEN
  370. begin
  371. // getlabel(hl4);
  372. IF unsigned
  373. THEN
  374. exprasmList.concat(Taicpu.Op_sym(A_JMPL,S_NO,hl4))
  375. ELSE
  376. exprasmList.concat(Taicpu.Op_sym(A_JMPL,S_NO,hl4));
  377. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  378. cg.a_label(exprasmlist,hl4);
  379. end;
  380. end;
  381. end;
  382. procedure TSparcAddNode.emit_op_right_left(op:TAsmOp);
  383. begin
  384. {left must be a register}
  385. with left,location,exprasmlist do
  386. case Right.Location.Loc of
  387. LOC_REGISTER,LOC_CREGISTER:
  388. concat(taicpu.op_reg_reg_reg(op,Register,Right.Location.register,register));
  389. LOC_REFERENCE,LOC_CREFERENCE :
  390. begin
  391. location_force_reg(exprasmlist,Right.Location,OS_32,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  392. concat(taicpu.op_reg_reg_reg(op,register,Right.Location.register,register));
  393. end;
  394. LOC_CONSTANT:
  395. concat(taicpu.op_reg_const_reg(op,register,Right.Location.value,register));
  396. else
  397. InternalError(200203232);
  398. end;
  399. end;
  400. procedure TSparcAddNode.set_result_location(cmpOp,unsigned:Boolean);
  401. begin
  402. IF cmpOp
  403. THEN
  404. begin
  405. location_reset(location,LOC_FLAGS,OS_NO);
  406. location.resflags:=GetResFlags(unsigned);
  407. end
  408. ELSE
  409. location_copy(location,left.location);
  410. end;
  411. function def_opsize(p1:tdef):topsize;
  412. begin
  413. case p1.size of
  414. 1:def_opsize:=S_B;
  415. 2:def_opsize:=S_W;
  416. 4:def_opsize:=S_L;
  417. 8:def_opsize:=S_L;
  418. else
  419. InternalError(130820001);
  420. end;
  421. end;
  422. procedure TSparcAddNode.pass_2;
  423. {is also being used for "xor", and "mul", "sub", or and comparative operators}
  424. var
  425. popeax,popedx,pushedfpu,mboverflow,cmpop:Boolean;
  426. op:TAsmOp;
  427. power:LongInt;
  428. OpSize:TOpSize;
  429. unsigned:Boolean;{true, if unsigned types are compared}
  430. extra_not:Boolean;
  431. cgop:TOpCg;
  432. begin
  433. {to make it more readable, string and set (not smallset!) have their own
  434. procedures }
  435. case left.resulttype.def.deftype of
  436. orddef:
  437. if is_boolean(left.resulttype.def)and is_boolean(right.resulttype.def)
  438. then{handling boolean expressions}
  439. second_addboolean
  440. else if is_64bitint(left.resulttype.def)
  441. then{64bit operations}
  442. InternalError(20020726);//second_add64bit;
  443. stringdef:
  444. InternalError(20020726);//second_addstring;
  445. setdef:
  446. {normalsets are already handled in pass1}
  447. if(tsetdef(left.resulttype.def).settype<>smallset)
  448. then
  449. internalerror(200109041)
  450. else
  451. InternalError(20020726);//second_addsmallset;
  452. arraydef :
  453. InternalError(2002110600);
  454. floatdef :
  455. InternalError(20020726);//second_addfloat;
  456. end;
  457. {defaults}
  458. extra_not:=false;
  459. mboverflow:=false;
  460. cmpop:=false;
  461. unsigned:=not(is_signed(left.resulttype.def))or
  462. not(is_signed(right.resulttype.def));
  463. opsize:=def_opsize(left.resulttype.def);
  464. pass_left_and_right;
  465. if(left.resulttype.def.deftype=pointerdef)or
  466. (right.resulttype.def.deftype=pointerdef)or
  467. (is_class_or_interface(right.resulttype.def)and is_class_or_interface(left.resulttype.def)) or
  468. (left.resulttype.def.deftype=classrefdef) or
  469. (left.resulttype.def.deftype=procvardef) or
  470. ((left.resulttype.def.deftype=enumdef)and(left.resulttype.def.size=4))or
  471. ((left.resulttype.def.deftype=orddef)and(torddef(left.resulttype.def).typ in [s32bit,u32bit]))or
  472. ((right.resulttype.def.deftype=orddef)and(torddef(right.resulttype.def).typ in [s32bit,u32bit]))
  473. then
  474. begin
  475. case NodeType of
  476. addn:
  477. begin
  478. op:=A_ADD;
  479. mboverflow:=true;
  480. end;
  481. muln:
  482. begin
  483. IF unsigned
  484. THEN
  485. op:=A_UMUL
  486. ELSE
  487. op:=A_SMUL;
  488. mboverflow:=true;
  489. end;
  490. subn:
  491. begin
  492. op:=A_SUB;
  493. mboverflow:=true;
  494. end;
  495. ltn,lten,
  496. gtn,gten,
  497. equaln,unequaln:
  498. begin
  499. op:=A_CMP;
  500. cmpop:=true;
  501. end;
  502. xorn:
  503. op:=A_XOR;
  504. orn:
  505. op:=A_OR;
  506. andn:
  507. op:=A_AND;
  508. else
  509. CGMessage(type_e_mismatch);
  510. end;
  511. { Convert flags to register first }
  512. if(left.location.loc=LOC_FLAGS)
  513. then
  514. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  515. if (right.location.loc=LOC_FLAGS)
  516. then
  517. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  518. left_must_be_reg(OpSize,false);
  519. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  520. location_freetemp(exprasmlist,right.location);
  521. location_release(exprasmlist,right.location);
  522. if cmpop and(left.location.loc<>LOC_CREGISTER)
  523. then
  524. begin
  525. location_freetemp(exprasmlist,left.location);
  526. location_release(exprasmlist,left.location);
  527. end;
  528. set_result_location(cmpop,unsigned);
  529. end;
  530. end;
  531. procedure TSparcAddNode.pass_left_and_right;
  532. var
  533. pushedregs:tmaybesave;
  534. tmpreg:tregister;
  535. pushedfpu:boolean;
  536. begin
  537. { calculate the operator which is more difficult }
  538. firstcomplex(self);
  539. { in case of constant put it to the left }
  540. if (left.nodetype=ordconstn)
  541. then
  542. swapleftright;
  543. secondpass(left);
  544. { are too few registers free? }
  545. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  546. if location.loc=LOC_FPUREGISTER
  547. then
  548. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  549. else
  550. pushedfpu:=false;
  551. secondpass(right);
  552. maybe_restore(exprasmlist,left.location,pushedregs);
  553. if pushedfpu
  554. then
  555. begin
  556. tmpreg := rg.getregisterfpu(exprasmlist);
  557. cg.a_loadfpu_loc_reg(exprasmlist,left.location,tmpreg);
  558. location_reset(left.location,LOC_FPUREGISTER,left.location.size);
  559. left.location.register := tmpreg;
  560. end;
  561. end;
  562. begin
  563. cAddNode:=TSparcAddNode;
  564. end.
  565. {
  566. $Log$
  567. Revision 1.4 2002-12-30 21:17:22 mazen
  568. - unit cga no more used in sparc compiler.
  569. Revision 1.3 2002/12/25 20:59:49 mazen
  570. - many emitXXX removed from cga.pas in order to remove that file.
  571. Revision 1.2 2002/12/22 19:26:32 mazen
  572. * many internal errors related to unimplemented nodes are fixed
  573. Revision 1.1 2002/12/21 23:21:47 mazen
  574. + added support for the shift nodes
  575. + added debug output on screen with -an command line option
  576. Revision 1.10 2002/11/25 17:43:28 peter
  577. * splitted defbase in defutil,symutil,defcmp
  578. * merged isconvertable and is_equal into compare_defs(_ext)
  579. * made operator search faster by walking the list only once
  580. Revision 1.9 2002/11/10 19:07:46 mazen
  581. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  582. Revision 1.8 2002/11/06 15:34:00 mazen
  583. *** empty log message ***
  584. Revision 1.7 2002/11/06 11:31:24 mazen
  585. * op_reg_reg_reg don't need any more a TOpSize parameter
  586. Revision 1.6 2002/11/05 16:15:00 mazen
  587. *** empty log message ***
  588. Revision 1.5 2002/10/22 13:43:01 mazen
  589. - cga.pas redueced to an empty unit
  590. Revision 1.4 2002/10/10 20:23:57 mazen
  591. * tabs replaces by spaces
  592. }