naddcpu.pas 19 KB

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