ncpuadd.pas 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250
  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 clear_left_right(cmpop:Boolean);
  27. procedure second_addboolean;
  28. procedure second_add64bit;
  29. procedure second_addfloat;
  30. function GetResFlags(unsigned:Boolean):TResFlags;
  31. procedure emit_compare(unsigned:boolean);
  32. procedure left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  33. procedure emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  34. procedure emit_op_right_left(op:TAsmOp);
  35. procedure Load_left_right(cmpop,load_constants:Boolean);
  36. procedure pass_left_and_right;
  37. procedure set_result_location(cmpOp,unsigned:Boolean);
  38. end;
  39. implementation
  40. uses
  41. globtype,systems,
  42. cutils,verbose,globals,
  43. symconst,symdef,SymType,paramgr,
  44. aasmbase,aasmtai,aasmcpu,defutil,htypechk,
  45. cgbase,pass_2,regvars,
  46. cpupara,
  47. ncon,nset,
  48. ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  49. const
  50. opsize_2_cgSize:array[S_B..S_L]of TCgSize=(OS_8,OS_16,OS_32);
  51. procedure TSparcAddNode.clear_left_right(cmpop:Boolean);
  52. begin
  53. if(right.location.loc in [LOC_REGISTER,LOC_FPUREGISTER])and(cmpop or(location.register.enum <> right.location.register.enum))
  54. then
  55. begin
  56. rg.UnGetRegisterInt(exprasmlist,right.location.register);
  57. if is_64bitint(right.resulttype.def)
  58. then
  59. rg.UnGetRegisterInt(exprasmlist,right.location.registerhigh);
  60. end;
  61. if(left.location.loc in [LOC_REGISTER,LOC_FPUREGISTER])and(cmpop or(location.register.enum <> left.location.register.enum))
  62. then
  63. begin
  64. rg.UnGetRegisterInt(exprasmlist,left.location.register);
  65. if is_64bitint(left.resulttype.def)
  66. then
  67. rg.UnGetRegisterInt(exprasmlist,left.location.registerhigh);
  68. end;
  69. end;
  70. procedure TSparcAddNode.second_addboolean;
  71. var
  72. cgop:TOpCg;
  73. cgsize:TCgSize;
  74. cmpop,isjump:boolean;
  75. otl,ofl:tasmlabel;
  76. pushedregs:TMaybeSave;
  77. begin
  78. { calculate the operator which is more difficult }
  79. firstcomplex(self);
  80. cmpop:=false;
  81. if (torddef(left.resulttype.def).typ=bool8bit) or
  82. (torddef(right.resulttype.def).typ=bool8bit)
  83. then
  84. cgsize:=OS_8
  85. else if (torddef(left.resulttype.def).typ=bool16bit) or
  86. (torddef(right.resulttype.def).typ=bool16bit)
  87. then
  88. cgsize:=OS_16
  89. else
  90. cgsize:=OS_32;
  91. if (cs_full_boolean_eval in aktlocalswitches) or
  92. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn])
  93. then
  94. begin
  95. if left.nodetype in [ordconstn,realconstn]
  96. then
  97. swapleftright;
  98. isjump:=(left.location.loc=LOC_JUMP);
  99. if isjump
  100. then
  101. begin
  102. otl:=truelabel;
  103. objectlibrary.getlabel(truelabel);
  104. ofl:=falselabel;
  105. objectlibrary.getlabel(falselabel);
  106. end;
  107. secondpass(left);
  108. if left.location.loc in [LOC_FLAGS,LOC_JUMP]
  109. then
  110. location_force_reg(exprasmlist,left.location,cgsize,false);
  111. if isjump
  112. then
  113. begin
  114. truelabel:=otl;
  115. falselabel:=ofl;
  116. end;
  117. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  118. isjump:=(right.location.loc=LOC_JUMP);
  119. if isjump
  120. then
  121. begin
  122. otl:=truelabel;
  123. objectlibrary.getlabel(truelabel);
  124. ofl:=falselabel;
  125. objectlibrary.getlabel(falselabel);
  126. end;
  127. secondpass(right);
  128. maybe_restore(exprasmlist,left.location,pushedregs);
  129. if right.location.loc in [LOC_FLAGS,LOC_JUMP]
  130. then
  131. location_force_reg(exprasmlist,right.location,cgsize,false);
  132. if isjump
  133. then
  134. begin
  135. truelabel:=otl;
  136. falselabel:=ofl;
  137. end;
  138. cmpop := nodetype in [ltn,lten,gtn,gten,equaln,unequaln];
  139. { set result location }
  140. if not cmpop
  141. then
  142. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  143. else
  144. location_reset(location,LOC_FLAGS,OS_NO);
  145. load_left_right(cmpop,false);
  146. if (left.location.loc = LOC_CONSTANT)
  147. then
  148. swapleftright;
  149. { compare the }
  150. case nodetype of
  151. ltn,lten,gtn,gten,
  152. equaln,unequaln :
  153. begin
  154. if (right.location.loc <> LOC_CONSTANT)
  155. then
  156. exprasmlist.concat(taicpu.op_reg_reg(A_JMPL,left.location.register,right.location.register))
  157. else
  158. exprasmlist.concat(taicpu.op_reg_const(A_JMPL,left.location.register,longint(right.location.value)));
  159. location.resflags := GetResFlags(true);
  160. end;
  161. else
  162. begin
  163. case nodetype of
  164. xorn :
  165. cgop:=OP_XOR;
  166. orn :
  167. cgop:=OP_OR;
  168. andn :
  169. cgop:=OP_AND;
  170. else
  171. internalerror(200203247);
  172. end;
  173. if right.location.loc <> LOC_CONSTANT
  174. then
  175. cg.a_op_reg_reg_reg(exprasmlist,cgop,OS_INT,left.location.register,right.location.register,location.register)
  176. else
  177. cg.a_op_const_reg_reg(exprasmlist,cgop,OS_INT,right.location.value,left.location.register,location.register);
  178. end;
  179. end;
  180. end
  181. else
  182. begin
  183. // just to make sure we free the right registers
  184. cmpop := true;
  185. case nodetype of
  186. andn,
  187. orn :
  188. begin
  189. location_reset(location,LOC_JUMP,OS_NO);
  190. case nodetype of
  191. andn :
  192. begin
  193. otl:=truelabel;
  194. objectlibrary.getlabel(truelabel);
  195. secondpass(left);
  196. maketojumpbool(exprasmlist,left,lr_load_regvars);
  197. cg.a_label(exprasmlist,truelabel);
  198. truelabel:=otl;
  199. end;
  200. orn :
  201. begin
  202. ofl:=falselabel;
  203. objectlibrary.getlabel(falselabel);
  204. secondpass(left);
  205. maketojumpbool(exprasmlist,left,lr_load_regvars);
  206. cg.a_label(exprasmlist,falselabel);
  207. falselabel:=ofl;
  208. end;
  209. else
  210. CGMessage(type_e_mismatch);
  211. end;
  212. secondpass(right);
  213. maketojumpbool(exprasmlist,right,lr_load_regvars);
  214. end;
  215. end;
  216. end;
  217. clear_left_right(CmpOp);
  218. end;
  219. function TSparcAddNode.GetResFlags(unsigned:Boolean):TResFlags;
  220. begin
  221. case NodeType of
  222. equaln:
  223. GetResFlags:=F_E;
  224. unequaln:
  225. GetResFlags:=F_NE;
  226. else
  227. if not(unsigned)
  228. then
  229. if nf_swaped IN flags
  230. then
  231. case NodeType of
  232. ltn:
  233. GetResFlags:=F_G;
  234. lten:
  235. GetResFlags:=F_GE;
  236. gtn:
  237. GetResFlags:=F_L;
  238. gten:
  239. GetResFlags:=F_LE;
  240. end
  241. else
  242. case NodeType of
  243. ltn:
  244. GetResFlags:=F_L;
  245. lten:
  246. GetResFlags:=F_LE;
  247. gtn:
  248. GetResFlags:=F_G;
  249. gten:
  250. GetResFlags:=F_GE;
  251. end
  252. else
  253. if nf_swaped IN Flags
  254. then
  255. case NodeType of
  256. ltn:
  257. GetResFlags:=F_A;
  258. lten:
  259. GetResFlags:=F_AE;
  260. gtn:
  261. GetResFlags:=F_B;
  262. gten:
  263. GetResFlags:=F_BE;
  264. end
  265. else
  266. case NodeType of
  267. ltn:
  268. GetResFlags:=F_B;
  269. lten:
  270. GetResFlags:=F_BE;
  271. gtn:
  272. GetResFlags:=F_A;
  273. gten:
  274. GetResFlags:=F_AE;
  275. end;
  276. end;
  277. end;
  278. procedure TSparcAddNode.left_must_be_reg(OpSize:TOpSize;NoSwap:Boolean);
  279. begin
  280. if(left.location.loc=LOC_REGISTER)
  281. then
  282. exit;
  283. {left location is not a register}
  284. if(not NoSwap)and(right.location.loc=LOC_REGISTER)
  285. then{right is register so we can swap the locations}
  286. begin
  287. location_swap(left.location,right.location);
  288. toggleflag(nf_swaped);
  289. end
  290. else
  291. begin
  292. {maybe we can reuse a constant register when the operation is a comparison that
  293. doesn't change the value of the register}
  294. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  295. end;
  296. end;
  297. procedure TSparcAddNode.emit_generic_code(op:TAsmOp;OpSize:TOpSize;unsigned,extra_not,mboverflow:Boolean);
  298. var
  299. power:LongInt;
  300. hl4:TAsmLabel;
  301. begin
  302. { at this point, left.location.loc should be LOC_REGISTER }
  303. with ExprAsmList do
  304. if right.location.loc=LOC_REGISTER
  305. then
  306. begin
  307. { right.location is a LOC_REGISTER }
  308. { when swapped another result register }
  309. if(nodetype=subn)and(nf_swaped in flags)
  310. then
  311. begin
  312. if extra_not
  313. then
  314. Concat(Taicpu.Op_reg(A_NOT,left.location.register));
  315. Concat(Taicpu.Op_reg_reg_reg(Op,right.location.register,left.location.register,right.location.register));
  316. { newly swapped also set swapped flag }
  317. location_swap(left.location,right.location);
  318. toggleflag(nf_swaped);
  319. end
  320. else
  321. begin
  322. if extra_not
  323. then
  324. Concat(Taicpu.Op_reg(A_NOT,right.location.register));
  325. // emit_reg_reg(op,opsize,right.location.register,left.location.register);
  326. exprasmList.concat(Taicpu.Op_reg_reg_reg(Op,right.location.register,left.location.register,right.location.register));
  327. end;
  328. end
  329. ELSE
  330. begin
  331. { right.location is not a LOC_REGISTER }
  332. IF(nodetype=subn)AND(nf_swaped IN flags)
  333. THEN
  334. begin
  335. IF extra_not
  336. THEN
  337. exprasmList.concat(Taicpu.Op_reg(A_NOT,left.location.register));
  338. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  339. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  340. // emit_reg_reg(op,opsize,left.location.register,R_EDI);
  341. // emit_reg_reg(A_MOV,opsize,R_EDI,left.location.register);
  342. // rg.ungetregisterint(exprasmlist,R_EDI);
  343. end
  344. ELSE
  345. begin
  346. { Optimizations when right.location is a constant value }
  347. IF(op=A_CMP)AND(nodetype IN [equaln,unequaln])AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=0)
  348. THEN
  349. begin
  350. // emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  351. end
  352. ELSE IF(op=A_ADD)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  353. THEN
  354. with ExprAsmList,left.location do
  355. begin
  356. concat(TAiCpu.op_reg_const_reg(A_ADD,register,1,register));
  357. end
  358. ELSE IF(op=A_SUB)AND(right.location.loc=LOC_CONSTANT)AND(right.location.value=1)AND NOT(cs_check_overflow in aktlocalswitches)
  359. THEN
  360. begin
  361. exprasmList.concat(Taicpu.Op_reg(A_DEC,left.location.register));
  362. end
  363. ELSE IF(op=A_SMUL)AND(right.location.loc=LOC_CONSTANT)AND(ispowerof2(right.location.value,power))AND NOT(cs_check_overflow in aktlocalswitches)
  364. THEN
  365. begin
  366. exprasmList.concat(Taicpu.Op_const_reg(A_SLL,power,left.location.register));
  367. end
  368. ELSE
  369. begin
  370. IF extra_not
  371. THEN
  372. begin
  373. // rg.getexplicitregisterint(exprasmlist,R_EDI);
  374. // cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  375. // emit_reg(A_NOT,S_L,R_EDI);
  376. // emit_reg_reg(A_AND,S_L,R_EDI,left.location.register);
  377. // rg.ungetregisterint(exprasmlist,R_EDI);
  378. end
  379. ELSE
  380. begin
  381. emit_op_right_left(op);
  382. end;
  383. end;
  384. end;
  385. end;
  386. { only in case of overflow operations }
  387. { produce overflow code }
  388. { we must put it here directly, because sign of operation }
  389. { is in unsigned VAR!! }
  390. IF mboverflow
  391. THEN
  392. begin
  393. IF cs_check_overflow IN aktlocalswitches
  394. THEN
  395. begin
  396. // getlabel(hl4);
  397. IF unsigned
  398. THEN
  399. exprasmList.concat(Taicpu.Op_sym(A_JMPL,S_NO,hl4))
  400. ELSE
  401. exprasmList.concat(Taicpu.Op_sym(A_JMPL,S_NO,hl4));
  402. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  403. cg.a_label(exprasmlist,hl4);
  404. end;
  405. end;
  406. end;
  407. procedure TSparcAddNode.emit_compare(unsigned:boolean);
  408. var
  409. op:tasmop;
  410. tmpreg:tregister;
  411. useconst:boolean;
  412. begin
  413. // get the constant on the right if there is one
  414. if(left.location.loc=LOC_CONSTANT)
  415. then
  416. swapleftright;
  417. // can we use an immediate, or do we have to load the
  418. // constant in a register first?
  419. if(right.location.loc=LOC_CONSTANT)
  420. then
  421. begin
  422. {$ifdef ExtDebug}
  423. if (right.location.size in [OS_64,OS_S64]) and (hi(right.location.valueqword)<>0) and ((hi(right.location.valueqword)<>$ffffffff) or unsigned)
  424. then
  425. internalerror(2002080301);
  426. {$endif extdebug}
  427. if (nodetype in [equaln,unequaln])
  428. then
  429. if (unsigned and
  430. (right.location.value > high(word))) or
  431. (not unsigned and
  432. (longint(right.location.value) < low(smallint)) or
  433. (longint(right.location.value) > high(smallint))) then
  434. { we can then maybe use a constant in the 'othersigned' case
  435. (the sign doesn't matter for // equal/unequal)}
  436. unsigned := not unsigned;
  437. if (unsigned and
  438. ((right.location.value) <= high(word))) or
  439. (not(unsigned) and
  440. (longint(right.location.value) >= low(smallint)) and
  441. (longint(right.location.value) <= high(smallint)))
  442. then
  443. useconst := true
  444. else
  445. begin
  446. useconst := false;
  447. tmpreg := cg.get_scratch_reg_int(exprasmlist,OS_INT);
  448. cg.a_load_const_reg(exprasmlist,OS_INT,right.location.value,tmpreg);
  449. end
  450. end
  451. else
  452. useconst := false;
  453. location.loc := LOC_FLAGS;
  454. location.resflags:=getresflags(False);
  455. op:=A_CMP;
  456. if (right.location.loc = LOC_CONSTANT)
  457. then
  458. if useconst
  459. then
  460. exprasmlist.concat(taicpu.op_reg_const(op,
  461. left.location.register,longint(right.location.value)))
  462. else
  463. begin
  464. exprasmlist.concat(taicpu.op_reg_reg(op,left.location.register,tmpreg));
  465. cg.free_scratch_reg(exprasmlist,tmpreg);
  466. end
  467. else
  468. exprasmlist.concat(taicpu.op_reg_reg(op,
  469. left.location.register,right.location.register));
  470. end;
  471. procedure TSparcAddNode.emit_op_right_left(op:TAsmOp);
  472. begin
  473. {left must be a register}
  474. with left,location,exprasmlist do
  475. case Right.Location.Loc of
  476. LOC_REGISTER,LOC_CREGISTER:
  477. concat(taicpu.op_reg_reg_reg(op,Register,Right.Location.register,register));
  478. LOC_REFERENCE,LOC_CREFERENCE :
  479. begin
  480. location_force_reg(exprasmlist,Right.Location,OS_32,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  481. concat(taicpu.op_reg_reg_reg(op,register,Right.Location.register,register));
  482. end;
  483. LOC_CONSTANT:
  484. concat(taicpu.op_reg_const_reg(op,register,Right.Location.value,register));
  485. else
  486. InternalError(200203232);
  487. end;
  488. end;
  489. procedure TSparcAddNode.second_add64bit;
  490. var
  491. op : TOpCG;
  492. op1,op2 : TAsmOp;
  493. hl4 : tasmlabel;
  494. cmpop,
  495. unsigned : boolean;
  496. r : Tregister;
  497. procedure emit_cmp64_hi;
  498. var
  499. oldleft, oldright: tlocation;
  500. begin
  501. // put the high part of the location in the low part
  502. location_copy(oldleft,left.location);
  503. location_copy(oldright,right.location);
  504. if left.location.loc = LOC_CONSTANT
  505. then
  506. left.location.valueqword := left.location.valueqword shr 32
  507. else
  508. left.location.registerlow := left.location.registerhigh;
  509. if right.location.loc = LOC_CONSTANT
  510. then
  511. right.location.valueqword := right.location.valueqword shr 32
  512. else
  513. right.location.registerlow := right.location.registerhigh;
  514. // and call the normal emit_compare
  515. emit_compare(unsigned);
  516. location_copy(left.location,oldleft);
  517. location_copy(right.location,oldright);
  518. end;
  519. procedure emit_cmp64_lo;
  520. begin
  521. emit_compare(true);
  522. end;
  523. procedure firstjmp64bitcmp;
  524. var
  525. oldnodetype: tnodetype;
  526. begin
  527. load_all_regvars(exprasmlist);
  528. { the jump the sequence is a little bit hairy }
  529. case nodetype of
  530. ltn,gtn:
  531. begin
  532. cg.a_jmp_flags(exprasmlist,getresflags(false),truelabel);
  533. { cheat a little bit for the negative test }
  534. toggleflag(nf_swaped);
  535. cg.a_jmp_flags(exprasmlist,getresflags(false),falselabel);
  536. toggleflag(nf_swaped);
  537. end;
  538. lten,gten:
  539. begin
  540. oldnodetype:=nodetype;
  541. if nodetype=lten then
  542. nodetype:=ltn
  543. else
  544. nodetype:=gtn;
  545. cg.a_jmp_flags(exprasmlist,getresflags(false),truelabel);
  546. { cheat for the negative test }
  547. if nodetype=ltn then
  548. nodetype:=gtn
  549. else
  550. nodetype:=ltn;
  551. cg.a_jmp_flags(exprasmlist,getresflags(false),falselabel);
  552. nodetype:=oldnodetype;
  553. end;
  554. equaln:
  555. begin
  556. nodetype := unequaln;
  557. cg.a_jmp_flags(exprasmlist,getresflags(true),falselabel);
  558. nodetype := equaln;
  559. end;
  560. unequaln:
  561. begin
  562. cg.a_jmp_flags(exprasmlist,getresflags(true),truelabel);
  563. end;
  564. end;
  565. end;
  566. procedure secondjmp64bitcmp;
  567. begin
  568. { the jump the sequence is a little bit hairy }
  569. case nodetype of
  570. ltn,gtn,lten,gten:
  571. begin
  572. { the comparison of the low dword always has }
  573. { to be always unsigned! }
  574. cg.a_jmp_flags(exprasmlist,getresflags(false),truelabel);
  575. cg.a_jmp_always(exprasmlist,falselabel);
  576. end;
  577. equaln:
  578. begin
  579. nodetype := unequaln;
  580. cg.a_jmp_flags(exprasmlist,getresflags(true),falselabel);
  581. cg.a_jmp_always(exprasmlist,truelabel);
  582. nodetype := equaln;
  583. end;
  584. unequaln:
  585. begin
  586. cg.a_jmp_flags(exprasmlist,getresflags(true),truelabel);
  587. cg.a_jmp_always(exprasmlist,falselabel);
  588. end;
  589. end;
  590. end;
  591. var
  592. tempreg64: tregister64;
  593. begin
  594. firstcomplex(self);
  595. pass_left_and_right;
  596. cmpop:=false;
  597. unsigned:=((left.resulttype.def.deftype=orddef) and
  598. (torddef(left.resulttype.def).typ=u64bit)) or
  599. ((right.resulttype.def.deftype=orddef) and
  600. (torddef(right.resulttype.def).typ=u64bit));
  601. case nodetype of
  602. addn :
  603. begin
  604. op:=OP_ADD;
  605. end;
  606. subn :
  607. begin
  608. op:=OP_SUB;
  609. end;
  610. ltn,lten,
  611. gtn,gten,
  612. equaln,unequaln:
  613. begin
  614. op:=OP_NONE;
  615. cmpop:=true;
  616. end;
  617. xorn:
  618. op:=OP_XOR;
  619. orn:
  620. op:=OP_OR;
  621. andn:
  622. op:=OP_AND;
  623. muln:
  624. begin
  625. { should be handled in pass_1 (JM) }
  626. internalerror(200109051);
  627. end;
  628. else
  629. internalerror(2002072705);
  630. end;
  631. if not cmpop then
  632. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def));
  633. load_left_right(cmpop,(cs_check_overflow in aktlocalswitches) and (nodetype in [addn,subn]));
  634. if not(cs_check_overflow in aktlocalswitches) or
  635. not(nodetype in [addn,subn]) then
  636. begin
  637. case nodetype of
  638. ltn,lten,
  639. gtn,gten:
  640. begin
  641. emit_cmp64_hi;
  642. firstjmp64bitcmp;
  643. emit_cmp64_lo;
  644. secondjmp64bitcmp;
  645. end;
  646. equaln,unequaln:
  647. begin
  648. // instead of doing a complicated compare, do
  649. // (left.hi xor right.hi) or (left.lo xor right.lo)
  650. // (somewhate optimized so that no superfluous 'mr's are
  651. // generated)
  652. if (left.location.loc = LOC_CONSTANT) then
  653. swapleftright;
  654. if (right.location.loc = LOC_CONSTANT) then
  655. begin
  656. if left.location.loc = LOC_REGISTER then
  657. begin
  658. tempreg64.reglo := left.location.registerlow;
  659. tempreg64.reghi := left.location.registerhigh;
  660. end
  661. else
  662. begin
  663. if (right.location.valueqword <> 0)
  664. then
  665. tempreg64.reglo := cg.get_scratch_reg_int(exprasmlist,OS_INT)
  666. else
  667. tempreg64.reglo := left.location.registerlow;
  668. if ((right.location.valueqword shr 32) <> 0) then
  669. tempreg64.reghi := cg.get_scratch_reg_int(exprasmlist,OS_INT)
  670. else
  671. tempreg64.reghi := left.location.registerhigh;
  672. end;
  673. if (right.location.valueqword <> 0) then
  674. { negative values can be handled using SUB, }
  675. { positive values < 65535 using XOR. }
  676. if (longint(right.location.valueqword) >= -32767) and
  677. (longint(right.location.valueqword) < 0) then
  678. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,OS_INT,
  679. right.location.valueqword,
  680. left.location.registerlow,tempreg64.reglo)
  681. else
  682. cg.a_op_const_reg_reg(exprasmlist,OP_XOR,OS_INT,
  683. right.location.valueqword,
  684. left.location.registerlow,tempreg64.reglo);
  685. if ((right.location.valueqword shr 32) <> 0) then
  686. if (longint(right.location.valueqword shr 32) >= -32767) and
  687. (longint(right.location.valueqword shr 32) < 0) then
  688. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,OS_INT,
  689. right.location.valueqword shr 32,
  690. left.location.registerhigh,tempreg64.reghi)
  691. else
  692. cg.a_op_const_reg_reg(exprasmlist,OP_XOR,OS_INT,
  693. right.location.valueqword shr 32,
  694. left.location.registerhigh,tempreg64.reghi);
  695. end
  696. else
  697. begin
  698. tempreg64.reglo := cg.get_scratch_reg_int(exprasmlist,OS_INT);
  699. tempreg64.reghi := cg.get_scratch_reg_int(exprasmlist,OS_INT);
  700. cg64.a_op64_reg_reg_reg(exprasmlist,OP_XOR,
  701. left.location.register64,right.location.register64,
  702. tempreg64);
  703. end;
  704. r.enum:=R_G0;
  705. cg.a_reg_alloc(exprasmlist,r);
  706. exprasmlist.concat(taicpu.op_reg_reg_reg(A_OR,r,
  707. tempreg64.reglo,tempreg64.reghi));
  708. cg.a_reg_dealloc(exprasmlist,r);
  709. if (tempreg64.reglo.enum <> left.location.registerlow.enum) then
  710. cg.free_scratch_reg(exprasmlist,tempreg64.reglo);
  711. if (tempreg64.reghi.enum <> left.location.registerhigh.enum) then
  712. cg.free_scratch_reg(exprasmlist,tempreg64.reghi);
  713. location_reset(location,LOC_FLAGS,OS_NO);
  714. location.resflags := getresflags(true);
  715. end;
  716. xorn,orn,andn,addn:
  717. begin
  718. if (location.registerlow.enum = R_NO) then
  719. begin
  720. location.registerlow := rg.getregisterint(exprasmlist,OS_INT);
  721. location.registerhigh := rg.getregisterint(exprasmlist,OS_INT);
  722. end;
  723. if (left.location.loc = LOC_CONSTANT) then
  724. swapleftright;
  725. if (right.location.loc = LOC_CONSTANT) then
  726. cg64.a_op64_const_reg_reg(exprasmlist,op,right.location.valueqword,
  727. left.location.register64,location.register64)
  728. else
  729. cg64.a_op64_reg_reg_reg(exprasmlist,op,right.location.register64,
  730. left.location.register64,location.register64);
  731. end;
  732. subn:
  733. begin
  734. if (nf_swaped in flags) then
  735. swapleftright;
  736. if left.location.loc <> LOC_CONSTANT then
  737. begin
  738. if (location.registerlow.enum = R_NO) then
  739. begin
  740. location.registerlow := rg.getregisterint(exprasmlist,OS_INT);
  741. location.registerhigh := rg.getregisterint(exprasmlist,OS_INT);
  742. end;
  743. if right.location.loc <> LOC_CONSTANT then
  744. // reg64 - reg64
  745. cg64.a_op64_reg_reg_reg(exprasmlist,OP_SUB,
  746. right.location.register64,left.location.register64,
  747. location.register64)
  748. else
  749. // reg64 - const64
  750. cg64.a_op64_const_reg_reg(exprasmlist,OP_SUB,
  751. right.location.valueqword,left.location.register64,
  752. location.register64)
  753. end
  754. else if ((left.location.valueqword shr 32) = 0) then
  755. begin
  756. if (location.registerlow.enum = R_NO) then
  757. begin
  758. location.registerlow := rg.getregisterint(exprasmlist,OS_INT);
  759. location.registerhigh := rg.getregisterint(exprasmlist,OS_INT);
  760. end;
  761. if (int64(left.location.valueqword) >= low(smallint)) and
  762. (int64(left.location.valueqword) <= high(smallint))
  763. then
  764. begin
  765. // consts16 - reg64
  766. exprasmlist.concat(taicpu.op_reg_const_Reg(A_SUBcc,location.registerlow,left.location.value,right.location.registerlow));
  767. end
  768. else
  769. begin
  770. // const32 - reg64
  771. cg.a_load_const_reg(exprasmlist,OS_32,
  772. left.location.valueqword,location.registerlow);
  773. exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBcc,
  774. location.registerlow,location.registerlow,
  775. right.location.registerlow));
  776. end;
  777. exprasmlist.concat(taicpu.op_reg_reg(A_SUBcc,
  778. location.registerhigh,right.location.registerhigh));
  779. end
  780. else if (left.location.valueqword = 0) then
  781. begin
  782. // (const32 shl 32) - reg64
  783. if (location.registerlow.enum = R_NO) then
  784. begin
  785. location.registerlow := rg.getregisterint(exprasmlist,OS_INT);
  786. location.registerhigh := rg.getregisterint(exprasmlist,OS_INT);
  787. end;
  788. exprasmlist.concat(taicpu.op_reg_Const_reg(A_SUBcc,location.registerlow,0,right.location.registerlow));
  789. cg.a_load_const_reg(exprasmlist,OS_INT,
  790. left.location.valueqword shr 32,location.registerhigh);
  791. exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBcc,
  792. location.registerhigh,right.location.registerhigh,
  793. location.registerhigh));
  794. end
  795. else
  796. begin
  797. // const64 - reg64
  798. location_force_reg(exprasmlist,left.location,
  799. def_cgsize(left.resulttype.def),true);
  800. if (left.location.loc = LOC_REGISTER) then
  801. location.register64 := left.location.register64
  802. else if (location.registerlow.enum = R_NO) then
  803. begin
  804. location.registerlow := rg.getregisterint(exprasmlist,OS_INT);
  805. location.registerhigh := rg.getregisterint(exprasmlist,OS_INT);
  806. end;
  807. cg64.a_op64_reg_reg_reg(exprasmlist,OP_SUB,
  808. right.location.register64,left.location.register64,
  809. location.register64);
  810. end;
  811. end;
  812. else
  813. internalerror(2002072803);
  814. end;
  815. end
  816. else
  817. begin
  818. case nodetype of
  819. addn:
  820. begin
  821. op1 := A_ADDcc;
  822. op2 := A_ADDcc;
  823. end;
  824. subn:
  825. begin
  826. op1 := A_SUBcc;
  827. op2 := A_SUBcc;
  828. end;
  829. else
  830. internalerror(2002072806);
  831. end;
  832. exprasmlist.concat(taicpu.op_reg_reg_reg(op1,location.registerlow,
  833. left.location.registerlow,right.location.registerlow));
  834. exprasmlist.concat(taicpu.op_reg_reg_reg(op2,location.registerhigh,
  835. right.location.registerhigh,left.location.registerhigh));
  836. cg.g_overflowcheck(exprasmlist,self);
  837. end;
  838. { set result location }
  839. { (emit_compare sets it to LOC_FLAGS for compares, so set the }
  840. { real location only now) (JM) }
  841. if cmpop and
  842. not(nodetype in [equaln,unequaln]) then
  843. location_reset(location,LOC_JUMP,OS_NO);
  844. clear_left_right(cmpop);
  845. end;
  846. procedure TSparcAddNode.load_left_right(cmpop,load_constants:Boolean);
  847. procedure load_node(var n:tnode);
  848. begin
  849. case n.location.loc of
  850. LOC_REGISTER:
  851. if not cmpop
  852. then
  853. begin
  854. location.register := n.location.register;
  855. if is_64bitint(n.resulttype.def)
  856. then
  857. location.registerhigh := n.location.registerhigh;
  858. end;
  859. LOC_REFERENCE,LOC_CREFERENCE:
  860. begin
  861. location_force_reg(exprasmlist,n.location,def_cgsize(n.resulttype.def),false);
  862. if not cmpop
  863. then
  864. begin
  865. location.register := n.location.register;
  866. if is_64bitint(n.resulttype.def)
  867. then
  868. location.registerhigh := n.location.registerhigh;
  869. end;
  870. end;
  871. LOC_CONSTANT:
  872. begin
  873. if load_constants
  874. then
  875. begin
  876. location_force_reg(exprasmlist,n.location,def_cgsize(n.resulttype.def),false);
  877. if not cmpop
  878. then
  879. location.register := n.location.register;
  880. if is_64bitint(n.resulttype.def)
  881. then
  882. location.registerhigh := n.location.registerhigh;
  883. end;
  884. end;
  885. end;
  886. end;
  887. begin
  888. load_node(left);
  889. load_node(right);
  890. end;
  891. procedure TSparcAddNode.second_addfloat;
  892. var
  893. reg : tregister;
  894. op : TAsmOp;
  895. cmpop : boolean;
  896. r : Tregister;
  897. procedure location_force_fpureg(var l: tlocation);
  898. begin
  899. if not(l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
  900. begin
  901. reg := rg.getregisterfpu(exprasmlist);
  902. cg.a_loadfpu_loc_reg(exprasmlist,l,reg);
  903. location_freetemp(exprasmlist,l);
  904. location_release(exprasmlist,l);
  905. location_reset(l,LOC_FPUREGISTER,l.size);
  906. l.register := reg;
  907. end;
  908. end;
  909. begin
  910. pass_left_and_right;
  911. cmpop:=false;
  912. case nodetype of
  913. addn :
  914. op:=A_FADDs;
  915. muln :
  916. op:=A_FMULs;
  917. subn :
  918. op:=A_FSUBs;
  919. slashn :
  920. op:=A_FDIVs;
  921. ltn,lten,gtn,gten,
  922. equaln,unequaln :
  923. begin
  924. op:=A_FCMPs;
  925. cmpop:=true;
  926. end;
  927. else
  928. CGMessage(type_e_mismatch);
  929. end;
  930. // get the operands in the correct order, there are no special cases
  931. // here, everything is register-based
  932. if nf_swaped in flags then
  933. swapleftright;
  934. // put both operands in a register
  935. location_force_fpureg(right.location);
  936. location_force_fpureg(left.location);
  937. // initialize de result
  938. if not cmpop then
  939. begin
  940. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  941. if left.location.loc = LOC_FPUREGISTER then
  942. location.register := left.location.register
  943. else if right.location.loc = LOC_FPUREGISTER then
  944. location.register := right.location.register
  945. else
  946. location.register := rg.getregisterfpu(exprasmlist);
  947. end
  948. else
  949. begin
  950. location_reset(location,LOC_FLAGS,OS_NO);
  951. location.resflags := getresflags(true);
  952. end;
  953. // emit the actual operation
  954. if not cmpop then
  955. begin
  956. exprasmlist.concat(taicpu.op_reg_reg_reg(op,
  957. location.register,left.location.register,
  958. right.location.register))
  959. end
  960. else
  961. begin
  962. r.enum:=R_PSR;
  963. exprasmlist.concat(taicpu.op_reg_reg_reg(op,
  964. r,left.location.register,right.location.register))
  965. end;
  966. // clear_left_right(cmpop);
  967. end;
  968. procedure TSparcAddNode.set_result_location(cmpOp,unsigned:Boolean);
  969. begin
  970. IF cmpOp
  971. THEN
  972. begin
  973. location_reset(location,LOC_FLAGS,OS_NO);
  974. location.resflags:=GetResFlags(unsigned);
  975. end
  976. ELSE
  977. location_copy(location,left.location);
  978. end;
  979. function def_opsize(p1:tdef):topsize;
  980. begin
  981. case p1.size of
  982. 1:def_opsize:=S_B;
  983. 2:def_opsize:=S_W;
  984. 4:def_opsize:=S_L;
  985. 8:def_opsize:=S_L;
  986. else
  987. InternalError(130820001);
  988. end;
  989. end;
  990. procedure TSparcAddNode.pass_2;
  991. {is also being used for "xor", and "mul", "sub", or and comparative operators}
  992. var
  993. popeax,popedx,pushedfpu,mboverflow,cmpop:Boolean;
  994. op:TAsmOp;
  995. power:LongInt;
  996. OpSize:TOpSize;
  997. unsigned:Boolean;{true, if unsigned types are compared}
  998. extra_not:Boolean;
  999. cgop:TOpCg;
  1000. begin
  1001. {to make it more readable, string and set (not smallset!) have their own
  1002. procedures }
  1003. case left.resulttype.def.deftype of
  1004. orddef:
  1005. if is_boolean(left.resulttype.def)and is_boolean(right.resulttype.def)
  1006. then{handling boolean expressions}
  1007. begin
  1008. second_addboolean;
  1009. exit;
  1010. end
  1011. else if is_64bitint(left.resulttype.def)
  1012. then{64bit operations}
  1013. begin
  1014. second_add64bit;
  1015. exit;
  1016. end;
  1017. stringdef:
  1018. InternalError(20020726);//second_addstring;
  1019. setdef:
  1020. {normalsets are already handled in pass1}
  1021. if(tsetdef(left.resulttype.def).settype<>smallset)
  1022. then
  1023. internalerror(200109041)
  1024. else
  1025. InternalError(20020726);//second_addsmallset;
  1026. arraydef :
  1027. InternalError(2002110600);
  1028. floatdef :
  1029. begin
  1030. second_addfloat;
  1031. exit;
  1032. end;
  1033. end;
  1034. {defaults}
  1035. extra_not:=false;
  1036. mboverflow:=false;
  1037. cmpop:=nodetype in [ltn,lten,gtn,gten,equaln,unequaln];
  1038. unsigned:=not(is_signed(left.resulttype.def))or
  1039. not(is_signed(right.resulttype.def));
  1040. opsize:=def_opsize(left.resulttype.def);
  1041. pass_left_and_right;
  1042. { set result location }
  1043. if not cmpop
  1044. then
  1045. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  1046. else
  1047. location_reset(location,LOC_FLAGS,OS_NO);
  1048. load_left_right(cmpop,(cs_check_overflow in aktlocalswitches)and(nodetype in [addn,subn,muln]));
  1049. if(location.register.enum = R_NO)and not(cmpop)
  1050. then
  1051. location.register := rg.getregisterint(exprasmlist,OS_INT);
  1052. if not(cs_check_overflow in aktlocalswitches)or cmpop or (nodetype in [orn,andn,xorn])
  1053. then
  1054. begin
  1055. case NodeType of
  1056. addn:
  1057. begin
  1058. op:=A_ADD;
  1059. mboverflow:=true;
  1060. end;
  1061. muln:
  1062. begin
  1063. IF unsigned
  1064. THEN
  1065. op:=A_UMUL
  1066. ELSE
  1067. op:=A_SMUL;
  1068. mboverflow:=true;
  1069. end;
  1070. subn:
  1071. begin
  1072. op:=A_SUB;
  1073. mboverflow:=true;
  1074. end;
  1075. ltn,lten,
  1076. gtn,gten,
  1077. equaln,unequaln:
  1078. begin
  1079. op:=A_CMP;
  1080. cmpop:=true;
  1081. end;
  1082. xorn:
  1083. op:=A_XOR;
  1084. orn:
  1085. op:=A_OR;
  1086. andn:
  1087. op:=A_AND;
  1088. else
  1089. CGMessage(type_e_mismatch);
  1090. end;
  1091. { Convert flags to register first }
  1092. if(left.location.loc=LOC_FLAGS)
  1093. then
  1094. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  1095. if (right.location.loc=LOC_FLAGS)
  1096. then
  1097. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  1098. left_must_be_reg(OpSize,false);
  1099. if not cmpOp
  1100. then
  1101. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow)
  1102. else
  1103. emit_compare(unsigned);
  1104. location_freetemp(exprasmlist,right.location);
  1105. location_release(exprasmlist,right.location);
  1106. if cmpop and(left.location.loc<>LOC_CREGISTER)
  1107. then
  1108. begin
  1109. location_freetemp(exprasmlist,left.location);
  1110. location_release(exprasmlist,left.location);
  1111. end;
  1112. end;
  1113. clear_left_right(cmpop);
  1114. end;
  1115. procedure TSparcAddNode.pass_left_and_right;
  1116. var
  1117. pushedregs:tmaybesave;
  1118. tmpreg:tregister;
  1119. pushedfpu:boolean;
  1120. begin
  1121. { calculate the operator which is more difficult }
  1122. firstcomplex(self);
  1123. { in case of constant put it to the left }
  1124. if (left.nodetype=ordconstn)
  1125. then
  1126. swapleftright;
  1127. secondpass(left);
  1128. { are too few registers free? }
  1129. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  1130. if location.loc=LOC_FPUREGISTER
  1131. then
  1132. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  1133. else
  1134. pushedfpu:=false;
  1135. secondpass(right);
  1136. maybe_restore(exprasmlist,left.location,pushedregs);
  1137. if pushedfpu
  1138. then
  1139. begin
  1140. tmpreg := rg.getregisterfpu(exprasmlist);
  1141. cg.a_loadfpu_loc_reg(exprasmlist,left.location,tmpreg);
  1142. location_reset(left.location,LOC_FPUREGISTER,left.location.size);
  1143. left.location.register := tmpreg;
  1144. end;
  1145. end;
  1146. begin
  1147. cAddNode:=TSparcAddNode;
  1148. end.
  1149. {
  1150. $Log$
  1151. Revision 1.13 2003-05-07 15:05:37 mazen
  1152. * fixed generated code for compare instructions
  1153. Revision 1.12 2003/05/06 21:37:58 mazen
  1154. * adding emit_compare trying fixing compare bugs
  1155. Revision 1.11 2003/03/10 21:59:54 mazen
  1156. * fixing index overflow in handling new registers arrays.
  1157. Revision 1.10 2003/02/19 22:00:17 daniel
  1158. * Code generator converted to new register notation
  1159. - Horribily outdated todo.txt removed
  1160. Revision 1.9 2003/02/13 21:15:18 mazen
  1161. + Load_left_right and clear_left_right implemented fixing test0001 register
  1162. allocation bug.
  1163. Revision 1.8 2003/01/22 20:45:15 mazen
  1164. * making math code in RTL compiling.
  1165. *NB : This does NOT mean necessary that it will generate correct code!
  1166. Revision 1.7 2003/01/20 22:21:36 mazen
  1167. * many stuff related to RTL fixed
  1168. Revision 1.6 2003/01/08 18:43:58 daniel
  1169. * Tregister changed into a record
  1170. Revision 1.5 2003/01/07 22:03:40 mazen
  1171. * adding unequaln node support to sparc compiler
  1172. Revision 1.4 2002/12/30 21:17:22 mazen
  1173. - unit cga no more used in sparc compiler.
  1174. Revision 1.3 2002/12/25 20:59:49 mazen
  1175. - many emitXXX removed from cga.pas in order to remove that file.
  1176. Revision 1.2 2002/12/22 19:26:32 mazen
  1177. * many internal errors related to unimplemented nodes are fixed
  1178. Revision 1.1 2002/12/21 23:21:47 mazen
  1179. + added support for the shift nodes
  1180. + added debug output on screen with -an command line option
  1181. Revision 1.10 2002/11/25 17:43:28 peter
  1182. * splitted defbase in defutil,symutil,defcmp
  1183. * merged isconvertable and is_equal into compare_defs(_ext)
  1184. * made operator search faster by walking the list only once
  1185. Revision 1.9 2002/11/10 19:07:46 mazen
  1186. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  1187. Revision 1.8 2002/11/06 15:34:00 mazen
  1188. *** empty log message ***
  1189. Revision 1.7 2002/11/06 11:31:24 mazen
  1190. * op_reg_reg_reg don't need any more a TOpSize parameter
  1191. Revision 1.6 2002/11/05 16:15:00 mazen
  1192. *** empty log message ***
  1193. Revision 1.5 2002/10/22 13:43:01 mazen
  1194. - cga.pas redueced to an empty unit
  1195. Revision 1.4 2002/10/10 20:23:57 mazen
  1196. * tabs replaces by spaces
  1197. }