naddcpu.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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 naddcpu;
  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. FUNCTION GetResFlags(unsigned:Boolean):TResFlags;
  27. procedure left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  28. procedure emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  29. procedure emit_op_right_left(op:TAsmOp;OpSize:TOpsize);
  30. procedure pass_left_and_right;
  31. procedure set_result_location(cmpOp,unsigned:Boolean);
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,
  37. symconst,symdef,paramgr,
  38. aasmbase,aasmtai,aasmcpu,defbase,htypechk,
  39. cgbase,pass_2,regvars,
  40. cpupara,
  41. ncon,nset,
  42. cga,ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  43. const
  44. opsize_2_cgSize:array[S_B..S_L]of TCgSize=(OS_8,OS_16,OS_32);
  45. function TSparcAddNode.GetResFlags(unsigned:Boolean):TResFlags;
  46. begin
  47. case NodeType of
  48. equaln:
  49. GetResFlags:=F_E;
  50. unequaln:
  51. GetResFlags:=F_NE;
  52. else
  53. if not(unsigned)
  54. then
  55. if nf_swaped IN flags
  56. then
  57. case NodeType of
  58. ltn:
  59. GetResFlags:=F_G;
  60. lten:
  61. GetResFlags:=F_GE;
  62. gtn:
  63. GetResFlags:=F_L;
  64. gten:
  65. GetResFlags:=F_LE;
  66. end
  67. else
  68. case NodeType of
  69. ltn:
  70. GetResFlags:=F_L;
  71. lten:
  72. GetResFlags:=F_LE;
  73. gtn:
  74. GetResFlags:=F_G;
  75. gten:
  76. GetResFlags:=F_GE;
  77. end
  78. else
  79. if nf_swaped IN Flags
  80. then
  81. case NodeType of
  82. ltn:
  83. GetResFlags:=F_A;
  84. lten:
  85. GetResFlags:=F_AE;
  86. gtn:
  87. GetResFlags:=F_B;
  88. gten:
  89. GetResFlags:=F_BE;
  90. end
  91. else
  92. case NodeType of
  93. ltn:
  94. GetResFlags:=F_B;
  95. lten:
  96. GetResFlags:=F_BE;
  97. gtn:
  98. GetResFlags:=F_A;
  99. gten:
  100. GetResFlags:=F_AE;
  101. end;
  102. end;
  103. end;
  104. procedure TSparcAddNode.left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  105. begin
  106. if(left.location.loc<>LOC_REGISTER)
  107. then{left location is not a register}
  108. begin
  109. if(not NoSwap)and(right.location.loc=LOC_REGISTER)
  110. then{right is register so we can swap the locations}
  111. begin
  112. location_swap(left.location,right.location);
  113. toggleflag(nf_swaped);
  114. end
  115. else
  116. begin
  117. {maybe we can reuse a constant register when the operation is a comparison that
  118. doesn't change the value of the register}
  119. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype IN [ltn,lten,gtn,gten,equaln,unequaln]));
  120. end;
  121. end;
  122. end;
  123. procedure TSparcAddNode.emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  124. VAR
  125. power:LongInt;
  126. hl4:TAsmLabel;
  127. begin
  128. { at this point, left.location.loc should be LOC_REGISTER }
  129. if right.location.loc=LOC_REGISTER
  130. then
  131. begin
  132. { right.location is a LOC_REGISTER }
  133. { when swapped another result register }
  134. if(nodetype=subn)and(nf_swaped in flags)
  135. then
  136. begin
  137. if extra_not
  138. then
  139. emit_reg(A_NOT,S_L,left.location.register);
  140. emit_reg_reg(op,opsize,left.location.register,right.location.register);
  141. { newly swapped also set swapped flag }
  142. location_swap(left.location,right.location);
  143. toggleflag(nf_swaped);
  144. end
  145. else
  146. begin
  147. if extra_not
  148. then
  149. emit_reg(A_NOT,S_L,right.location.register);
  150. emit_reg_reg(op,opsize,right.location.register,left.location.register);
  151. end;
  152. end
  153. ELSE
  154. begin
  155. { right.location is not a LOC_REGISTER }
  156. IF(nodetype=subn)AND(nf_swaped IN flags)
  157. THEN
  158. begin
  159. IF extra_not
  160. THEN
  161. emit_reg(A_NOT,opsize,left.location.register);
  162. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  163. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  164. // emit_reg_reg(op,opsize,left.location.register,R_EDI);
  165. // emit_reg_reg(A_MOV,opsize,R_EDI,left.location.register);
  166. // rg.ungetregisterint(exprasmlist,R_EDI);
  167. end
  168. ELSE
  169. begin
  170. { Optimizations when right.location is a constant value }
  171. IF(op=A_CMP)AND(nodetype IN [equaln,unequaln])AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=0)
  172. THEN
  173. begin
  174. // emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  175. end
  176. ELSE IF(op=A_ADD)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  177. THEN
  178. begin
  179. emit_reg(A_INC,opsize,left.location.register);
  180. end
  181. ELSE IF(op=A_SUB)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  182. THEN
  183. begin
  184. emit_reg(A_DEC,opsize,left.location.register);
  185. end
  186. ELSE IF(op=A_SMUL)AND(right.location.loc=LOC_CONSTANT)AND(ispowerof2(right.location.value,power))AND NOT(cs_check_overflow in aktlocalswitches)
  187. THEN
  188. begin
  189. emit_const_reg(A_SLL,opsize,power,left.location.register);
  190. end
  191. ELSE
  192. begin
  193. IF extra_not
  194. THEN
  195. begin
  196. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  197. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  198. // emit_reg(A_NOT,S_L,R_EDI);
  199. // emit_reg_reg(A_AND,S_L,R_EDI,left.location.register);
  200. // rg.ungetregisterint(exprasmlist,R_EDI);
  201. end
  202. ELSE
  203. begin
  204. emit_op_right_left(op,opsize);
  205. end;
  206. end;
  207. end;
  208. end;
  209. { only in case of overflow operations }
  210. { produce overflow code }
  211. { we must put it here directly, because sign of operation }
  212. { is in unsigned VAR!! }
  213. IF mboverflow
  214. THEN
  215. begin
  216. IF cs_check_overflow IN aktlocalswitches
  217. THEN
  218. begin
  219. // getlabel(hl4);
  220. IF unsigned
  221. THEN
  222. emitjmp(C_NB,hl4)
  223. ELSE
  224. emitjmp(C_NO,hl4);
  225. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  226. cg.a_label(exprasmlist,hl4);
  227. end;
  228. end;
  229. end;
  230. procedure TSparcAddNode.emit_op_right_left(op:TAsmOp;OpSize:TOpsize);
  231. begin
  232. {left must be a register}
  233. with exprasmlist do
  234. case right.location.loc of
  235. LOC_REGISTER,LOC_CREGISTER:
  236. concat(taicpu.op_reg_reg(op,opsize,right.location.register,left.location.register));
  237. LOC_REFERENCE,LOC_CREFERENCE :
  238. concat(taicpu.op_ref_reg(op,opsize,right.location.reference,left.location.register));
  239. LOC_CONSTANT:
  240. concat(taicpu.op_const_reg(op,opsize,right.location.value,left.location.register));
  241. else
  242. InternalError(200203232);
  243. end;
  244. end;
  245. procedure TSparcAddNode.set_result_location(cmpOp,unsigned:Boolean);
  246. begin
  247. IF cmpOp
  248. THEN
  249. begin
  250. location_reset(location,LOC_FLAGS,OS_NO);
  251. location.resflags:=GetResFlags(unsigned);
  252. end
  253. ELSE
  254. location_copy(location,left.location);
  255. end;
  256. procedure TSparcAddNode.pass_2;
  257. {is also being used for "xor", and "mul", "sub", or and comparative operators}
  258. VAR
  259. popeax,popedx,pushedfpu,mboverflow,cmpop:Boolean;
  260. op:TAsmOp;
  261. power:LongInt;
  262. OpSize:TOpSize;
  263. unsigned:Boolean;{true, if unsigned types are compared}
  264. { is_in_dest if the result is put directly into }
  265. { the resulting refernce or varregister }
  266. {is_in_dest : boolean;}
  267. { true, if for sets subtractions the extra not should generated }
  268. extra_not:Boolean;
  269. begin
  270. {to make it more readable, string and set (not smallset!) have their own
  271. procedures }
  272. case left.resulttype.def.deftype of
  273. orddef:
  274. if is_boolean(left.resulttype.def)and is_boolean(right.resulttype.def)
  275. then{handling boolean expressions}
  276. begin
  277. InternalError(20020726);//second_addboolean;
  278. exit;
  279. end
  280. else if is_64bitint(left.resulttype.def)
  281. then{64bit operations}
  282. begin
  283. InternalError(20020726);//second_add64bit;
  284. exit;
  285. end;
  286. stringdef:
  287. begin
  288. InternalError(20020726);//second_addstring;
  289. exit;
  290. end;
  291. setdef:
  292. begin
  293. {normalsets are already handled in pass1}
  294. if(tsetdef(left.resulttype.def).settype<>smallset)
  295. then
  296. internalerror(200109041);
  297. InternalError(20020726);//second_addsmallset;
  298. exit;
  299. end;
  300. arraydef :
  301. begin
  302. end;
  303. floatdef :
  304. begin
  305. InternalError(20020726);//second_addfloat;
  306. exit;
  307. end;
  308. end;
  309. {defaults}
  310. {is_in_dest:=false;}
  311. extra_not:=false;
  312. mboverflow:=false;
  313. cmpop:=false;
  314. unsigned:=not(is_signed(left.resulttype.def))or not(is_signed(right.resulttype.def));
  315. opsize:=def_opsize(left.resulttype.def);
  316. pass_left_and_right;
  317. IF(left.resulttype.def.deftype=pointerdef)OR
  318. (right.resulttype.def.deftype=pointerdef) or
  319. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  320. (left.resulttype.def.deftype=classrefdef) or
  321. (left.resulttype.def.deftype=procvardef) or
  322. ((left.resulttype.def.deftype=enumdef)and(left.resulttype.def.size=4)) or
  323. ((left.resulttype.def.deftype=orddef)and(torddef(left.resulttype.def).typ in [s32bit,u32bit])) or
  324. ((right.resulttype.def.deftype=orddef)and(torddef(right.resulttype.def).typ in [s32bit,u32bit]))
  325. then
  326. begin
  327. case NodeType of
  328. addn:
  329. begin
  330. op:=A_ADD;
  331. mboverflow:=true;
  332. end;
  333. muln:
  334. begin
  335. IF unsigned
  336. THEN
  337. op:=A_UMUL
  338. ELSE
  339. op:=A_SMUL;
  340. mboverflow:=true;
  341. end;
  342. subn:
  343. begin
  344. op:=A_SUB;
  345. mboverflow:=true;
  346. end;
  347. ltn,lten,
  348. gtn,gten,
  349. equaln,unequaln:
  350. begin
  351. op:=A_CMP;
  352. cmpop:=true;
  353. end;
  354. xorn:
  355. op:=A_XOR;
  356. orn:
  357. op:=A_OR;
  358. andn:
  359. op:=A_AND;
  360. ELSE
  361. CGMessage(type_e_mismatch);
  362. end;
  363. { filter MUL, which requires special handling }
  364. IF op=A_UMUL
  365. THEN
  366. begin
  367. popeax:=false;
  368. popedx:=false;
  369. { here you need to free the symbol first }
  370. { left.location and right.location must }
  371. { only be freed when they are really released, }
  372. { because the optimizer NEEDS correct regalloc }
  373. { info!!! (JM) }
  374. { the location.register will be filled in later (JM) }
  375. location_reset(location,LOC_REGISTER,OS_INT);
  376. {$IfNDef NoShlMul}
  377. IF right.nodetype=ordconstn
  378. THEN
  379. swapleftright;
  380. IF(left.nodetype=ordconstn)and
  381. ispowerof2(tordconstnode(left).value, power)and
  382. not(cs_check_overflow in aktlocalswitches)
  383. THEN
  384. begin
  385. { This release will be moved after the next }
  386. { instruction by the optimizer. No need to }
  387. { release left.location, since it's a }
  388. { constant (JM) }
  389. location_release(exprasmlist,right.location);
  390. location.register:=rg.getregisterint(exprasmlist);
  391. cg.a_load_loc_reg(exprasmlist,right.location,location.register);
  392. cg.a_op_const_reg(exprasmlist,OP_SHL,power,location.register);
  393. end
  394. ELSE
  395. begin
  396. {$EndIf NoShlMul}
  397. {In SPARC there is no push/pop mechanism. There is a windowing mechanism using
  398. SAVE and RESTORE instructions.}
  399. //regstopush:=all_registers;
  400. //remove_non_regvars_from_loc(right.location,regstopush);
  401. //remove_non_regvars_from_loc(left.location,regstopush);
  402. {left.location can be R_EAX !!!}
  403. // rg.GetExplicitRegisterInt(exprasmlist,R_EDI);
  404. {load the left value}
  405. // cg.a_load_loc_reg(exprasmlist,left.location,R_EDI);
  406. // location_release(exprasmlist,left.location);
  407. { allocate EAX }
  408. // if R_EAX in rg.unusedregsint then
  409. // exprasmList.concat(tai_regalloc.Alloc(R_EAX));
  410. { load he right value }
  411. // cg.a_load_loc_reg(exprasmlist,right.location,R_EAX);
  412. // location_release(exprasmlist,right.location);
  413. { allocate EAX if it isn't yet allocated (JM) }
  414. // if (R_EAX in rg.unusedregsint) then
  415. // exprasmList.concat(tai_regalloc.Alloc(R_EAX));
  416. { also allocate EDX, since it is also modified by }
  417. { a mul (JM) }
  418. { if R_EDX in rg.unusedregsint then
  419. exprasmList.concat(tai_regalloc.Alloc(R_EDX));
  420. emit_reg(A_MUL,S_L,R_EDI);
  421. rg.ungetregisterint(exprasmlist,R_EDI);
  422. if R_EDX in rg.unusedregsint then
  423. exprasmList.concat(tai_regalloc.DeAlloc(R_EDX));
  424. if R_EAX in rg.unusedregsint then
  425. exprasmList.concat(tai_regalloc.DeAlloc(R_EAX));
  426. location.register:=rg.getregisterint(exprasmlist);
  427. emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
  428. if popedx then
  429. emit_reg(A_POP,S_L,R_EDX);
  430. if popeax then
  431. emit_reg(A_POP,S_L,R_EAX);}
  432. {$IfNDef NoShlMul}
  433. End;
  434. {$endif NoShlMul}
  435. location_freetemp(exprasmlist,left.location);
  436. location_freetemp(exprasmlist,right.location);
  437. exit;
  438. end;
  439. { Convert flags to register first }
  440. if (left.location.loc=LOC_FLAGS) then
  441. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  442. if (right.location.loc=LOC_FLAGS) then
  443. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  444. left_must_be_reg(OpSize,false);
  445. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  446. location_freetemp(exprasmlist,right.location);
  447. location_release(exprasmlist,right.location);
  448. if cmpop and
  449. (left.location.loc<>LOC_CREGISTER) then
  450. begin
  451. location_freetemp(exprasmlist,left.location);
  452. location_release(exprasmlist,left.location);
  453. end;
  454. set_result_location(cmpop,unsigned);
  455. end
  456. { 8/16 bit enum,char,wchar types }
  457. { else
  458. if ((left.resulttype.def.deftype=orddef) and
  459. (torddef(left.resulttype.def).typ in [uchar,uwidechar])) or
  460. ((left.resulttype.def.deftype=enumdef) and
  461. ((left.resulttype.def.size=1) or
  462. (left.resulttype.def.size=2))) then
  463. begin
  464. case nodetype of
  465. ltn,lten,gtn,gten,
  466. equaln,unequaln :
  467. cmpop:=true;
  468. else
  469. CGMessage(type_e_mismatch);
  470. end;
  471. left_must_be_reg(opsize,false);
  472. emit_op_right_left(A_CMP,opsize);
  473. location_freetemp(exprasmlist,right.location);
  474. location_release(exprasmlist,right.location);
  475. if left.location.loc<>LOC_CREGISTER then
  476. begin
  477. location_freetemp(exprasmlist,left.location);
  478. location_release(exprasmlist,left.location);
  479. end;
  480. set_result_location(true,true);
  481. end
  482. else
  483. CGMessage(type_e_mismatch);}
  484. end;
  485. procedure TSparcAddNode.pass_left_and_right;
  486. var
  487. pushedregs:tmaybesave;
  488. tmpreg:tregister;
  489. pushedfpu:boolean;
  490. begin
  491. { calculate the operator which is more difficult }
  492. firstcomplex(self);
  493. { in case of constant put it to the left }
  494. if (left.nodetype=ordconstn)
  495. then
  496. swapleftright;
  497. secondpass(left);
  498. { are too few registers free? }
  499. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  500. if location.loc=LOC_FPUREGISTER
  501. then
  502. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  503. else
  504. pushedfpu:=false;
  505. secondpass(right);
  506. maybe_restore(exprasmlist,left.location,pushedregs);
  507. if pushedfpu
  508. then
  509. begin
  510. tmpreg := rg.getregisterfpu(exprasmlist);
  511. cg.a_loadfpu_loc_reg(exprasmlist,left.location,tmpreg);
  512. location_reset(left.location,LOC_FPUREGISTER,left.location.size);
  513. left.location.register := tmpreg;
  514. end;
  515. end;
  516. begin
  517. cAddNode:=TSparcAddNode;
  518. end.
  519. {
  520. $Log$
  521. Revision 1.4 2002-10-10 20:23:57 mazen
  522. * tabs replaces by spaces
  523. }