naddcpu.pas 17 KB

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