nadd.pas 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Type checking and register allocation for add nodes
  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. }
  18. unit nadd;
  19. interface
  20. uses
  21. node;
  22. type
  23. taddnode = class(tbinopnode)
  24. procedure make_bool_equal_size;
  25. function firstpass : tnode;override;
  26. end;
  27. tcaddnode : class of taddnode;
  28. var
  29. { caddnode is used to create nodes of the add type }
  30. { the virtual constructor allows to assign }
  31. { another class type to caddnode => processor }
  32. { specific node types can be created }
  33. caddnode : tcaddnode;
  34. function isbinaryoverloaded(var p : ptree) : boolean;
  35. implementation
  36. uses
  37. globtype,systems,tokens,
  38. cobjects,verbose,globals,
  39. symconst,symtable,aasm,types,
  40. cpuinfo,
  41. {$ifdef newcg}
  42. cgbase,
  43. {$else newcg}
  44. hcodegen,
  45. {$endif newcg}
  46. htypechk,pass_1,
  47. cpubase,tccnv
  48. ;
  49. function isbinaryoverloaded(var p : ptree) : boolean;
  50. var
  51. rd,ld : pdef;
  52. t : ptree;
  53. optoken : ttoken;
  54. begin
  55. isbinaryoverloaded:=false;
  56. { overloaded operator ? }
  57. { load easier access variables }
  58. rd:=p^.right^.resulttype;
  59. ld:=p^.left^.resulttype;
  60. if isbinaryoperatoroverloadable(ld,rd,voiddef,p^.treetype) then
  61. begin
  62. isbinaryoverloaded:=true;
  63. {!!!!!!!!! handle paras }
  64. case p^.treetype of
  65. { the nil as symtable signs firstcalln that this is
  66. an overloaded operator }
  67. addn:
  68. optoken:=_PLUS;
  69. subn:
  70. optoken:=_MINUS;
  71. muln:
  72. optoken:=_STAR;
  73. starstarn:
  74. optoken:=_STARSTAR;
  75. slashn:
  76. optoken:=_SLASH;
  77. ltn:
  78. optoken:=tokens._lt;
  79. gtn:
  80. optoken:=tokens._gt;
  81. lten:
  82. optoken:=_lte;
  83. gten:
  84. optoken:=_gte;
  85. equaln,unequaln :
  86. optoken:=_EQUAL;
  87. symdifn :
  88. optoken:=_SYMDIF;
  89. modn :
  90. optoken:=_OP_MOD;
  91. orn :
  92. optoken:=_OP_OR;
  93. xorn :
  94. optoken:=_OP_XOR;
  95. andn :
  96. optoken:=_OP_AND;
  97. divn :
  98. optoken:=_OP_DIV;
  99. shln :
  100. optoken:=_OP_SHL;
  101. shrn :
  102. optoken:=_OP_SHR;
  103. else
  104. exit;
  105. end;
  106. t:=gencallnode(overloaded_operators[optoken],nil);
  107. { we have to convert p^.left and p^.right into
  108. callparanodes }
  109. if t^.symtableprocentry=nil then
  110. begin
  111. CGMessage(parser_e_operator_not_overloaded);
  112. putnode(t);
  113. end
  114. else
  115. begin
  116. inc(t^.symtableprocentry^.refs);
  117. t^.left:=gencallparanode(p^.left,nil);
  118. t^.left:=gencallparanode(p^.right,t^.left);
  119. if p^.treetype=unequaln then
  120. t:=gensinglenode(notn,t);
  121. firstpass(t);
  122. putnode(p);
  123. p:=t;
  124. end;
  125. end;
  126. end;
  127. {*****************************************************************************
  128. FirstAdd
  129. *****************************************************************************}
  130. {$ifdef fpc}
  131. {$maxfpuregisters 0}
  132. {$endif fpc}
  133. procedure taddnode.make_bool_equal_size;
  134. begin
  135. if porddef(left^.resulttype)^.typ>porddef(right^.resulttype)^.typ then
  136. begin
  137. right:=gentypeconvnode(right,porddef(left^.resulttype));
  138. right^.convtyp:=tc_bool_2_int;
  139. right^.explizit:=true;
  140. firstpass(right);
  141. end
  142. else
  143. if porddef(left^.resulttype)^.typ<porddef(right^.resulttype)^.typ then
  144. begin
  145. left:=gentypeconvnode(left,porddef(right^.resulttype));
  146. left^.convtyp:=tc_bool_2_int;
  147. left^.explizit:=true;
  148. firstpass(left);
  149. end;
  150. end;
  151. function taddnode.pass_1 : tnode;
  152. var
  153. t,hp : ptree;
  154. ot,
  155. lt,rt : ttreetyp;
  156. rv,lv : TConstExprInt;
  157. rvd,lvd : bestreal;
  158. resdef,
  159. rd,ld : pdef;
  160. tempdef : pdef;
  161. concatstrings : boolean;
  162. { to evalute const sets }
  163. resultset : pconstset;
  164. i : longint;
  165. b : boolean;
  166. convdone : boolean;
  167. s1,s2 : pchar;
  168. l1,l2 : longint;
  169. begin
  170. pass_1:=nil;
  171. { first do the two subtrees }
  172. firstpass(left);
  173. firstpass(right);
  174. if codegenerror then
  175. exit;
  176. { convert array constructors to sets, because there is no other operator
  177. possible for array constructors }
  178. if is_array_constructor(left^.resulttype) then
  179. arrayconstructor_to_set(left);
  180. if is_array_constructor(right^.resulttype) then
  181. arrayconstructor_to_set(right);
  182. { both left and right need to be valid }
  183. set_varstate(left,true);
  184. set_varstate(right,true);
  185. { load easier access variables }
  186. lt:=left^.treetype;
  187. rt:=right^.treetype;
  188. rd:=right^.resulttype;
  189. ld:=left^.resulttype;
  190. convdone:=false;
  191. if isbinaryoverloaded(p) then
  192. exit;
  193. { compact consts }
  194. { convert int consts to real consts, if the }
  195. { other operand is a real const }
  196. if (rt=realconstn) and is_constintnode(left) then
  197. begin
  198. t:=genrealconstnode(left^.value,right^.resulttype);
  199. disposetree(left);
  200. left:=t;
  201. lt:=realconstn;
  202. end;
  203. if (lt=realconstn) and is_constintnode(right) then
  204. begin
  205. t:=genrealconstnode(right^.value,left^.resulttype);
  206. disposetree(right);
  207. right:=t;
  208. rt:=realconstn;
  209. end;
  210. { both are int constants, also allow operations on two equal enums
  211. in fpc mode (Needed for conversion of C code) }
  212. if ((lt=ordconstn) and (rt=ordconstn)) and
  213. ((is_constintnode(left) and is_constintnode(right)) or
  214. (is_constboolnode(left) and is_constboolnode(right) and
  215. (treetype in [ltn,lten,gtn,gten,equaln,unequaln,andn,xorn,orn]))) then
  216. begin
  217. { return a boolean for boolean operations (and,xor,or) }
  218. if is_constboolnode(left) then
  219. resdef:=booldef
  220. else
  221. resdef:=s32bitdef;
  222. lv:=left^.value;
  223. rv:=right^.value;
  224. case treetype of
  225. addn : t:=genordinalconstnode(lv+rv,resdef);
  226. subn : t:=genordinalconstnode(lv-rv,resdef);
  227. muln : t:=genordinalconstnode(lv*rv,resdef);
  228. xorn : t:=genordinalconstnode(lv xor rv,resdef);
  229. orn : t:=genordinalconstnode(lv or rv,resdef);
  230. andn : t:=genordinalconstnode(lv and rv,resdef);
  231. ltn : t:=genordinalconstnode(ord(lv<rv),booldef);
  232. lten : t:=genordinalconstnode(ord(lv<=rv),booldef);
  233. gtn : t:=genordinalconstnode(ord(lv>rv),booldef);
  234. gten : t:=genordinalconstnode(ord(lv>=rv),booldef);
  235. equaln : t:=genordinalconstnode(ord(lv=rv),booldef);
  236. unequaln : t:=genordinalconstnode(ord(lv<>rv),booldef);
  237. slashn : begin
  238. { int/int becomes a real }
  239. if int(rv)=0 then
  240. begin
  241. Message(parser_e_invalid_float_operation);
  242. t:=genrealconstnode(0,bestrealdef^);
  243. end
  244. else
  245. t:=genrealconstnode(int(lv)/int(rv),bestrealdef^);
  246. firstpass(t);
  247. end;
  248. else
  249. CGMessage(type_e_mismatch);
  250. end;
  251. firstpass(t);
  252. { the caller disposes the old tree }
  253. pass_1:=t;
  254. exit;
  255. end;
  256. { both real constants ? }
  257. if (lt=realconstn) and (rt=realconstn) then
  258. begin
  259. lvd:=left^.value_real;
  260. rvd:=right^.value_real;
  261. case treetype of
  262. addn : t:=genrealconstnode(lvd+rvd,bestrealdef^);
  263. subn : t:=genrealconstnode(lvd-rvd,bestrealdef^);
  264. muln : t:=genrealconstnode(lvd*rvd,bestrealdef^);
  265. starstarn,
  266. caretn : begin
  267. if lvd<0 then
  268. begin
  269. Message(parser_e_invalid_float_operation);
  270. t:=genrealconstnode(0,bestrealdef^);
  271. end
  272. else if lvd=0 then
  273. t:=genrealconstnode(1.0,bestrealdef^)
  274. else
  275. t:=genrealconstnode(exp(ln(lvd)*rvd),bestrealdef^);
  276. end;
  277. slashn :
  278. begin
  279. if rvd=0 then
  280. begin
  281. Message(parser_e_invalid_float_operation);
  282. t:=genrealconstnode(0,bestrealdef^);
  283. end
  284. else
  285. t:=genrealconstnode(lvd/rvd,bestrealdef^);
  286. end;
  287. ltn : t:=genordinalconstnode(ord(lvd<rvd),booldef);
  288. lten : t:=genordinalconstnode(ord(lvd<=rvd),booldef);
  289. gtn : t:=genordinalconstnode(ord(lvd>rvd),booldef);
  290. gten : t:=genordinalconstnode(ord(lvd>=rvd),booldef);
  291. equaln : t:=genordinalconstnode(ord(lvd=rvd),booldef);
  292. unequaln : t:=genordinalconstnode(ord(lvd<>rvd),booldef);
  293. else
  294. CGMessage(type_e_mismatch);
  295. end;
  296. firstpass(t);
  297. pass_1:=t;
  298. exit;
  299. end;
  300. { concating strings ? }
  301. concatstrings:=false;
  302. s1:=nil;
  303. s2:=nil;
  304. if (lt=ordconstn) and (rt=ordconstn) and
  305. is_char(ld) and is_char(rd) then
  306. begin
  307. s1:=strpnew(char(byte(left^.value)));
  308. s2:=strpnew(char(byte(right^.value)));
  309. l1:=1;
  310. l2:=1;
  311. concatstrings:=true;
  312. end
  313. else
  314. if (lt=stringconstn) and (rt=ordconstn) and is_char(rd) then
  315. begin
  316. s1:=getpcharcopy(left);
  317. l1:=left^.length;
  318. s2:=strpnew(char(byte(right^.value)));
  319. l2:=1;
  320. concatstrings:=true;
  321. end
  322. else
  323. if (lt=ordconstn) and (rt=stringconstn) and is_char(ld) then
  324. begin
  325. s1:=strpnew(char(byte(left^.value)));
  326. l1:=1;
  327. s2:=getpcharcopy(right);
  328. l2:=right^.length;
  329. concatstrings:=true;
  330. end
  331. else if (lt=stringconstn) and (rt=stringconstn) then
  332. begin
  333. s1:=getpcharcopy(left);
  334. l1:=left^.length;
  335. s2:=getpcharcopy(right);
  336. l2:=right^.length;
  337. concatstrings:=true;
  338. end;
  339. { I will need to translate all this to ansistrings !!! }
  340. if concatstrings then
  341. begin
  342. case treetype of
  343. addn :
  344. t:=genpcharconstnode(concatansistrings(s1,s2,l1,l2),l1+l2);
  345. ltn :
  346. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)<0),booldef);
  347. lten :
  348. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)<=0),booldef);
  349. gtn :
  350. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)>0),booldef);
  351. gten :
  352. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)>=0),booldef);
  353. equaln :
  354. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)=0),booldef);
  355. unequaln :
  356. t:=genordinalconstnode(byte(compareansistrings(s1,s2,l1,l2)<>0),booldef);
  357. end;
  358. ansistringdispose(s1,l1);
  359. ansistringdispose(s2,l2);
  360. firstpass(t);
  361. pass_1:=t;
  362. exit;
  363. end;
  364. { if both are orddefs then check sub types }
  365. if (ld^.deftype=orddef) and (rd^.deftype=orddef) then
  366. begin
  367. { 2 booleans ? }
  368. if is_boolean(ld) and is_boolean(rd) then
  369. begin
  370. case treetype of
  371. andn,
  372. orn:
  373. begin
  374. make_bool_equal_size(p);
  375. calcregisters(p,0,0,0);
  376. location.loc:=LOC_JUMP;
  377. end;
  378. xorn,ltn,lten,gtn,gten:
  379. begin
  380. make_bool_equal_size(p);
  381. if (left^.location.loc in [LOC_JUMP,LOC_FLAGS]) and
  382. (left^.location.loc in [LOC_JUMP,LOC_FLAGS]) then
  383. calcregisters(p,2,0,0)
  384. else
  385. calcregisters(p,1,0,0);
  386. end;
  387. unequaln,
  388. equaln:
  389. begin
  390. make_bool_equal_size(p);
  391. { Remove any compares with constants }
  392. if (left^.treetype=ordconstn) then
  393. begin
  394. hp:=right;
  395. b:=(left^.value<>0);
  396. ot:=treetype;
  397. disposetree(left);
  398. putnode(p);
  399. p:=hp;
  400. if (not(b) and (ot=equaln)) or
  401. (b and (ot=unequaln)) then
  402. begin
  403. p:=gensinglenode(notn,p);
  404. firstpass(p);
  405. end;
  406. exit;
  407. end;
  408. if (right^.treetype=ordconstn) then
  409. begin
  410. hp:=left;
  411. b:=(right^.value<>0);
  412. ot:=treetype;
  413. disposetree(right);
  414. putnode(p);
  415. p:=hp;
  416. if (not(b) and (ot=equaln)) or
  417. (b and (ot=unequaln)) then
  418. begin
  419. p:=gensinglenode(notn,p);
  420. firstpass(p);
  421. end;
  422. exit;
  423. end;
  424. if (left^.location.loc in [LOC_JUMP,LOC_FLAGS]) and
  425. (left^.location.loc in [LOC_JUMP,LOC_FLAGS]) then
  426. calcregisters(p,2,0,0)
  427. else
  428. calcregisters(p,1,0,0);
  429. end;
  430. else
  431. CGMessage(type_e_mismatch);
  432. end;
  433. { these one can't be in flags! }
  434. if treetype in [xorn,unequaln,equaln] then
  435. begin
  436. if left^.location.loc=LOC_FLAGS then
  437. begin
  438. left:=gentypeconvnode(left,porddef(left^.resulttype));
  439. left^.convtyp:=tc_bool_2_int;
  440. left^.explizit:=true;
  441. firstpass(left);
  442. end;
  443. if right^.location.loc=LOC_FLAGS then
  444. begin
  445. right:=gentypeconvnode(right,porddef(right^.resulttype));
  446. right^.convtyp:=tc_bool_2_int;
  447. right^.explizit:=true;
  448. firstpass(right);
  449. end;
  450. { readjust registers }
  451. calcregisters(p,1,0,0);
  452. end;
  453. convdone:=true;
  454. end
  455. else
  456. { Both are chars? only convert to shortstrings for addn }
  457. if is_char(rd) and is_char(ld) then
  458. begin
  459. if treetype=addn then
  460. begin
  461. left:=gentypeconvnode(left,cshortstringdef);
  462. right:=gentypeconvnode(right,cshortstringdef);
  463. firstpass(left);
  464. firstpass(right);
  465. { here we call STRCOPY }
  466. procinfo^.flags:=procinfo^.flags or pi_do_call;
  467. calcregisters(p,0,0,0);
  468. location.loc:=LOC_MEM;
  469. end
  470. else
  471. calcregisters(p,1,0,0);
  472. convdone:=true;
  473. end
  474. { is there a 64 bit type ? }
  475. else if ((porddef(rd)^.typ=s64bit) or (porddef(ld)^.typ=s64bit)) and
  476. { the / operator is handled later }
  477. (treetype<>slashn) then
  478. begin
  479. if (porddef(ld)^.typ<>s64bit) then
  480. begin
  481. left:=gentypeconvnode(left,cs64bitdef);
  482. firstpass(left);
  483. end;
  484. if (porddef(rd)^.typ<>s64bit) then
  485. begin
  486. right:=gentypeconvnode(right,cs64bitdef);
  487. firstpass(right);
  488. end;
  489. calcregisters(p,2,0,0);
  490. convdone:=true;
  491. end
  492. else if ((porddef(rd)^.typ=u64bit) or (porddef(ld)^.typ=u64bit)) and
  493. { the / operator is handled later }
  494. (treetype<>slashn) then
  495. begin
  496. if (porddef(ld)^.typ<>u64bit) then
  497. begin
  498. left:=gentypeconvnode(left,cu64bitdef);
  499. firstpass(left);
  500. end;
  501. if (porddef(rd)^.typ<>u64bit) then
  502. begin
  503. right:=gentypeconvnode(right,cu64bitdef);
  504. firstpass(right);
  505. end;
  506. calcregisters(p,2,0,0);
  507. convdone:=true;
  508. end
  509. else
  510. { is there a cardinal? }
  511. if ((porddef(rd)^.typ=u32bit) or (porddef(ld)^.typ=u32bit)) and
  512. { the / operator is handled later }
  513. (treetype<>slashn) then
  514. begin
  515. { convert constants to u32bit }
  516. {$ifndef cardinalmulfix}
  517. if (porddef(ld)^.typ<>u32bit) then
  518. begin
  519. { s32bit will be used for when the other is also s32bit }
  520. { the following line doesn't make any sense: it's the same as }
  521. { if ((porddef(rd)^.typ=u32bit) or (porddef(ld)^.typ=u32bit)) and }
  522. { (porddef(ld)^.typ<>u32bit) and (porddef(rd)^.typ=s32bit) then }
  523. { which can be simplified to }
  524. { if ((porddef(rd)^.typ=u32bit) and (porddef(rd)^.typ=s32bit) then }
  525. { which can never be true (JM) }
  526. if (porddef(rd)^.typ=s32bit) and (lt<>ordconstn) then
  527. left:=gentypeconvnode(left,s32bitdef)
  528. else
  529. left:=gentypeconvnode(left,u32bitdef);
  530. firstpass(left);
  531. end;
  532. if (porddef(rd)^.typ<>u32bit) then
  533. begin
  534. { s32bit will be used for when the other is also s32bit }
  535. if (porddef(ld)^.typ=s32bit) and (rt<>ordconstn) then
  536. right:=gentypeconvnode(right,s32bitdef)
  537. else
  538. right:=gentypeconvnode(right,u32bitdef);
  539. firstpass(right);
  540. end;
  541. {$else cardinalmulfix}
  542. { only do a conversion if the nodes have different signs }
  543. if (porddef(rd)^.typ=u32bit) xor (porddef(ld)^.typ=u32bit) then
  544. if (porddef(rd)^.typ=u32bit) then
  545. begin
  546. { can we make them both unsigned? }
  547. if is_constintnode(left) and
  548. ((treetype <> subn) and
  549. (left^.value > 0)) then
  550. left:=gentypeconvnode(left,u32bitdef)
  551. else
  552. left:=gentypeconvnode(left,s32bitdef);
  553. firstpass(left);
  554. end
  555. else {if (porddef(ld)^.typ=u32bit) then}
  556. begin
  557. { can we make them both unsigned? }
  558. if is_constintnode(right) and
  559. (right^.value > 0) then
  560. right:=gentypeconvnode(right,u32bitdef)
  561. else
  562. right:=gentypeconvnode(right,s32bitdef);
  563. firstpass(right);
  564. end;
  565. {$endif cardinalmulfix}
  566. calcregisters(p,1,0,0);
  567. { for unsigned mul we need an extra register }
  568. { registers32:=left^.registers32+right^.registers32; }
  569. if treetype=muln then
  570. inc(registers32);
  571. convdone:=true;
  572. end;
  573. end
  574. else
  575. { left side a setdef, must be before string processing,
  576. else array constructor can be seen as array of char (PFV) }
  577. if (ld^.deftype=setdef) {or is_array_constructor(ld)} then
  578. begin
  579. { trying to add a set element? }
  580. if (treetype=addn) and (rd^.deftype<>setdef) then
  581. begin
  582. if (rt=setelementn) then
  583. begin
  584. if not(is_equal(psetdef(ld)^.elementtype.def,rd)) then
  585. CGMessage(type_e_set_element_are_not_comp);
  586. end
  587. else
  588. CGMessage(type_e_mismatch)
  589. end
  590. else
  591. begin
  592. if not(treetype in [addn,subn,symdifn,muln,equaln,unequaln
  593. {$IfNDef NoSetInclusion}
  594. ,lten,gten
  595. {$EndIf NoSetInclusion}
  596. ]) then
  597. CGMessage(type_e_set_operation_unknown);
  598. { right def must be a also be set }
  599. if (rd^.deftype<>setdef) or not(is_equal(rd,ld)) then
  600. CGMessage(type_e_set_element_are_not_comp);
  601. end;
  602. { ranges require normsets }
  603. if (psetdef(ld)^.settype=smallset) and
  604. (rt=setelementn) and
  605. assigned(right^.right) then
  606. begin
  607. { generate a temporary normset def }
  608. tempdef:=new(psetdef,init(psetdef(ld)^.elementtype.def,255));
  609. left:=gentypeconvnode(left,tempdef);
  610. firstpass(left);
  611. dispose(tempdef,done);
  612. ld:=left^.resulttype;
  613. end;
  614. { if the destination is not a smallset then insert a typeconv
  615. which loads a smallset into a normal set }
  616. if (psetdef(ld)^.settype<>smallset) and
  617. (psetdef(rd)^.settype=smallset) then
  618. begin
  619. if (right^.treetype=setconstn) then
  620. begin
  621. t:=gensetconstnode(right^.value_set,psetdef(left^.resulttype));
  622. t^.left:=right^.left;
  623. putnode(right);
  624. right:=t;
  625. end
  626. else
  627. right:=gentypeconvnode(right,psetdef(left^.resulttype));
  628. firstpass(right);
  629. end;
  630. { do constant evaluation }
  631. if (right^.treetype=setconstn) and
  632. not assigned(right^.left) and
  633. (left^.treetype=setconstn) and
  634. not assigned(left^.left) then
  635. begin
  636. new(resultset);
  637. case treetype of
  638. addn : begin
  639. for i:=0 to 31 do
  640. resultset^[i]:=
  641. right^.value_set^[i] or left^.value_set^[i];
  642. t:=gensetconstnode(resultset,psetdef(ld));
  643. end;
  644. muln : begin
  645. for i:=0 to 31 do
  646. resultset^[i]:=
  647. right^.value_set^[i] and left^.value_set^[i];
  648. t:=gensetconstnode(resultset,psetdef(ld));
  649. end;
  650. subn : begin
  651. for i:=0 to 31 do
  652. resultset^[i]:=
  653. left^.value_set^[i] and not(right^.value_set^[i]);
  654. t:=gensetconstnode(resultset,psetdef(ld));
  655. end;
  656. symdifn : begin
  657. for i:=0 to 31 do
  658. resultset^[i]:=
  659. left^.value_set^[i] xor right^.value_set^[i];
  660. t:=gensetconstnode(resultset,psetdef(ld));
  661. end;
  662. unequaln : begin
  663. b:=true;
  664. for i:=0 to 31 do
  665. if right^.value_set^[i]=left^.value_set^[i] then
  666. begin
  667. b:=false;
  668. break;
  669. end;
  670. t:=genordinalconstnode(ord(b),booldef);
  671. end;
  672. equaln : begin
  673. b:=true;
  674. for i:=0 to 31 do
  675. if right^.value_set^[i]<>left^.value_set^[i] then
  676. begin
  677. b:=false;
  678. break;
  679. end;
  680. t:=genordinalconstnode(ord(b),booldef);
  681. end;
  682. {$IfNDef NoSetInclusion}
  683. lten : Begin
  684. b := true;
  685. For i := 0 to 31 Do
  686. If (right^.value_set^[i] And left^.value_set^[i]) <>
  687. left^.value_set^[i] Then
  688. Begin
  689. b := false;
  690. Break
  691. End;
  692. t := genordinalconstnode(ord(b),booldef);
  693. End;
  694. gten : Begin
  695. b := true;
  696. For i := 0 to 31 Do
  697. If (left^.value_set^[i] And right^.value_set^[i]) <>
  698. right^.value_set^[i] Then
  699. Begin
  700. b := false;
  701. Break
  702. End;
  703. t := genordinalconstnode(ord(b),booldef);
  704. End;
  705. {$EndIf NoSetInclusion}
  706. end;
  707. dispose(resultset);
  708. disposetree(p);
  709. p:=t;
  710. firstpass(p);
  711. exit;
  712. end
  713. else
  714. if psetdef(ld)^.settype=smallset then
  715. begin
  716. { are we adding set elements ? }
  717. if right^.treetype=setelementn then
  718. calcregisters(p,2,0,0)
  719. else
  720. calcregisters(p,1,0,0);
  721. location.loc:=LOC_REGISTER;
  722. end
  723. else
  724. begin
  725. calcregisters(p,0,0,0);
  726. { here we call SET... }
  727. procinfo^.flags:=procinfo^.flags or pi_do_call;
  728. location.loc:=LOC_MEM;
  729. end;
  730. convdone:=true;
  731. end
  732. else
  733. { compare pchar to char arrays by addresses
  734. like BP/Delphi }
  735. if (is_pchar(ld) and is_chararray(rd)) or
  736. (is_pchar(rd) and is_chararray(ld)) then
  737. begin
  738. if is_chararray(rd) then
  739. begin
  740. right:=gentypeconvnode(right,ld);
  741. firstpass(right);
  742. end
  743. else
  744. begin
  745. left:=gentypeconvnode(left,rd);
  746. firstpass(left);
  747. end;
  748. location.loc:=LOC_REGISTER;
  749. calcregisters(p,1,0,0);
  750. convdone:=true;
  751. end
  752. else
  753. { is one of the operands a string?,
  754. chararrays are also handled as strings (after conversion) }
  755. if (rd^.deftype=stringdef) or (ld^.deftype=stringdef) or
  756. ((is_chararray(rd) or is_char(rd)) and
  757. (is_chararray(ld) or is_char(ld))) then
  758. begin
  759. if is_widestring(rd) or is_widestring(ld) then
  760. begin
  761. if not(is_widestring(rd)) then
  762. right:=gentypeconvnode(right,cwidestringdef);
  763. if not(is_widestring(ld)) then
  764. left:=gentypeconvnode(left,cwidestringdef);
  765. resulttype:=cwidestringdef;
  766. { this is only for add, the comparisaion is handled later }
  767. location.loc:=LOC_REGISTER;
  768. end
  769. else if is_ansistring(rd) or is_ansistring(ld) then
  770. begin
  771. if not(is_ansistring(rd)) then
  772. right:=gentypeconvnode(right,cansistringdef);
  773. if not(is_ansistring(ld)) then
  774. left:=gentypeconvnode(left,cansistringdef);
  775. { we use ansistrings so no fast exit here }
  776. procinfo^.no_fast_exit:=true;
  777. resulttype:=cansistringdef;
  778. { this is only for add, the comparisaion is handled later }
  779. location.loc:=LOC_REGISTER;
  780. end
  781. else if is_longstring(rd) or is_longstring(ld) then
  782. begin
  783. if not(is_longstring(rd)) then
  784. right:=gentypeconvnode(right,clongstringdef);
  785. if not(is_longstring(ld)) then
  786. left:=gentypeconvnode(left,clongstringdef);
  787. resulttype:=clongstringdef;
  788. { this is only for add, the comparisaion is handled later }
  789. location.loc:=LOC_MEM;
  790. end
  791. else
  792. begin
  793. if not(is_shortstring(rd))
  794. {$ifdef newoptimizations2}
  795. {$ifdef i386}
  796. { shortstring + char handled seperately (JM) }
  797. and (not(cs_optimize in aktglobalswitches) or
  798. (treetype <> addn) or not(is_char(rd)))
  799. {$endif i386}
  800. {$endif newoptimizations2}
  801. then
  802. right:=gentypeconvnode(right,cshortstringdef);
  803. if not(is_shortstring(ld)) then
  804. left:=gentypeconvnode(left,cshortstringdef);
  805. resulttype:=cshortstringdef;
  806. { this is only for add, the comparisaion is handled later }
  807. location.loc:=LOC_MEM;
  808. end;
  809. { only if there is a type cast we need to do again }
  810. { the first pass }
  811. if left^.treetype=typeconvn then
  812. firstpass(left);
  813. if right^.treetype=typeconvn then
  814. firstpass(right);
  815. { here we call STRCONCAT or STRCMP or STRCOPY }
  816. procinfo^.flags:=procinfo^.flags or pi_do_call;
  817. if location.loc=LOC_MEM then
  818. calcregisters(p,0,0,0)
  819. else
  820. calcregisters(p,1,0,0);
  821. {$ifdef i386}
  822. { not always necessary, only if it is not a constant char and }
  823. { not a regvar, but don't know how to check this here (JM) }
  824. if is_char(rd) then
  825. inc(registers32);
  826. {$endif i386}
  827. convdone:=true;
  828. end
  829. else
  830. { is one a real float ? }
  831. if (rd^.deftype=floatdef) or (ld^.deftype=floatdef) then
  832. begin
  833. { if one is a fixed, then convert to f32bit }
  834. if ((rd^.deftype=floatdef) and (pfloatdef(rd)^.typ=f32bit)) or
  835. ((ld^.deftype=floatdef) and (pfloatdef(ld)^.typ=f32bit)) then
  836. begin
  837. if not is_integer(rd) or (treetype<>muln) then
  838. right:=gentypeconvnode(right,s32fixeddef);
  839. if not is_integer(ld) or (treetype<>muln) then
  840. left:=gentypeconvnode(left,s32fixeddef);
  841. firstpass(left);
  842. firstpass(right);
  843. calcregisters(p,1,0,0);
  844. location.loc:=LOC_REGISTER;
  845. end
  846. else
  847. { convert both to bestreal }
  848. begin
  849. right:=gentypeconvnode(right,bestrealdef^);
  850. left:=gentypeconvnode(left,bestrealdef^);
  851. firstpass(left);
  852. firstpass(right);
  853. calcregisters(p,0,1,0);
  854. location.loc:=LOC_FPU;
  855. end;
  856. convdone:=true;
  857. end
  858. else
  859. { pointer comperation and subtraction }
  860. if (rd^.deftype=pointerdef) and (ld^.deftype=pointerdef) then
  861. begin
  862. location.loc:=LOC_REGISTER;
  863. { right:=gentypeconvnode(right,ld); }
  864. { firstpass(right); }
  865. calcregisters(p,1,0,0);
  866. case treetype of
  867. equaln,unequaln :
  868. begin
  869. if is_equal(right^.resulttype,voidpointerdef) then
  870. begin
  871. right:=gentypeconvnode(right,ld);
  872. firstpass(right);
  873. end
  874. else if is_equal(left^.resulttype,voidpointerdef) then
  875. begin
  876. left:=gentypeconvnode(left,rd);
  877. firstpass(left);
  878. end
  879. else if not(is_equal(ld,rd)) then
  880. CGMessage(type_e_mismatch);
  881. end;
  882. ltn,lten,gtn,gten:
  883. begin
  884. if is_equal(right^.resulttype,voidpointerdef) then
  885. begin
  886. right:=gentypeconvnode(right,ld);
  887. firstpass(right);
  888. end
  889. else if is_equal(left^.resulttype,voidpointerdef) then
  890. begin
  891. left:=gentypeconvnode(left,rd);
  892. firstpass(left);
  893. end
  894. else if not(is_equal(ld,rd)) then
  895. CGMessage(type_e_mismatch);
  896. if not(cs_extsyntax in aktmoduleswitches) then
  897. CGMessage(type_e_mismatch);
  898. end;
  899. subn:
  900. begin
  901. if not(is_equal(ld,rd)) then
  902. CGMessage(type_e_mismatch);
  903. if not(cs_extsyntax in aktmoduleswitches) then
  904. CGMessage(type_e_mismatch);
  905. resulttype:=s32bitdef;
  906. exit;
  907. end;
  908. else CGMessage(type_e_mismatch);
  909. end;
  910. convdone:=true;
  911. end
  912. else
  913. if (rd^.deftype=objectdef) and (ld^.deftype=objectdef) and
  914. pobjectdef(rd)^.is_class and pobjectdef(ld)^.is_class then
  915. begin
  916. location.loc:=LOC_REGISTER;
  917. if pobjectdef(rd)^.is_related(pobjectdef(ld)) then
  918. right:=gentypeconvnode(right,ld)
  919. else
  920. left:=gentypeconvnode(left,rd);
  921. firstpass(right);
  922. firstpass(left);
  923. calcregisters(p,1,0,0);
  924. case treetype of
  925. equaln,unequaln : ;
  926. else CGMessage(type_e_mismatch);
  927. end;
  928. convdone:=true;
  929. end
  930. else
  931. if (rd^.deftype=classrefdef) and (ld^.deftype=classrefdef) then
  932. begin
  933. location.loc:=LOC_REGISTER;
  934. if pobjectdef(pclassrefdef(rd)^.pointertype.def)^.is_related(pobjectdef(
  935. pclassrefdef(ld)^.pointertype.def)) then
  936. right:=gentypeconvnode(right,ld)
  937. else
  938. left:=gentypeconvnode(left,rd);
  939. firstpass(right);
  940. firstpass(left);
  941. calcregisters(p,1,0,0);
  942. case treetype of
  943. equaln,unequaln : ;
  944. else CGMessage(type_e_mismatch);
  945. end;
  946. convdone:=true;
  947. end
  948. else
  949. { allows comperasion with nil pointer }
  950. if (rd^.deftype=objectdef) and
  951. pobjectdef(rd)^.is_class then
  952. begin
  953. location.loc:=LOC_REGISTER;
  954. left:=gentypeconvnode(left,rd);
  955. firstpass(left);
  956. calcregisters(p,1,0,0);
  957. case treetype of
  958. equaln,unequaln : ;
  959. else CGMessage(type_e_mismatch);
  960. end;
  961. convdone:=true;
  962. end
  963. else
  964. if (ld^.deftype=objectdef) and
  965. pobjectdef(ld)^.is_class then
  966. begin
  967. location.loc:=LOC_REGISTER;
  968. right:=gentypeconvnode(right,ld);
  969. firstpass(right);
  970. calcregisters(p,1,0,0);
  971. case treetype of
  972. equaln,unequaln : ;
  973. else CGMessage(type_e_mismatch);
  974. end;
  975. convdone:=true;
  976. end
  977. else
  978. if (rd^.deftype=classrefdef) then
  979. begin
  980. left:=gentypeconvnode(left,rd);
  981. firstpass(left);
  982. calcregisters(p,1,0,0);
  983. case treetype of
  984. equaln,unequaln : ;
  985. else CGMessage(type_e_mismatch);
  986. end;
  987. convdone:=true;
  988. end
  989. else
  990. if (ld^.deftype=classrefdef) then
  991. begin
  992. right:=gentypeconvnode(right,ld);
  993. firstpass(right);
  994. calcregisters(p,1,0,0);
  995. case treetype of
  996. equaln,unequaln : ;
  997. else
  998. CGMessage(type_e_mismatch);
  999. end;
  1000. convdone:=true;
  1001. end
  1002. else
  1003. { support procvar=nil,procvar<>nil }
  1004. if ((ld^.deftype=procvardef) and (rt=niln)) or
  1005. ((rd^.deftype=procvardef) and (lt=niln)) then
  1006. begin
  1007. calcregisters(p,1,0,0);
  1008. location.loc:=LOC_REGISTER;
  1009. case treetype of
  1010. equaln,unequaln : ;
  1011. else
  1012. CGMessage(type_e_mismatch);
  1013. end;
  1014. convdone:=true;
  1015. end
  1016. else
  1017. {$ifdef SUPPORT_MMX}
  1018. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(ld) and
  1019. is_mmx_able_array(rd) and is_equal(ld,rd) then
  1020. begin
  1021. firstpass(right);
  1022. firstpass(left);
  1023. case treetype of
  1024. addn,subn,xorn,orn,andn:
  1025. ;
  1026. { mul is a little bit restricted }
  1027. muln:
  1028. if not(mmx_type(left^.resulttype) in
  1029. [mmxu16bit,mmxs16bit,mmxfixed16]) then
  1030. CGMessage(type_e_mismatch);
  1031. else
  1032. CGMessage(type_e_mismatch);
  1033. end;
  1034. location.loc:=LOC_MMXREGISTER;
  1035. calcregisters(p,0,0,1);
  1036. convdone:=true;
  1037. end
  1038. else
  1039. {$endif SUPPORT_MMX}
  1040. { this is a little bit dangerous, also the left type }
  1041. { should be checked! This broke the mmx support }
  1042. if (rd^.deftype=pointerdef) or
  1043. is_zero_based_array(rd) then
  1044. begin
  1045. if is_zero_based_array(rd) then
  1046. begin
  1047. resulttype:=new(ppointerdef,init(parraydef(rd)^.elementtype));
  1048. right:=gentypeconvnode(right,resulttype);
  1049. firstpass(right);
  1050. end;
  1051. location.loc:=LOC_REGISTER;
  1052. left:=gentypeconvnode(left,s32bitdef);
  1053. firstpass(left);
  1054. calcregisters(p,1,0,0);
  1055. if treetype=addn then
  1056. begin
  1057. if not(cs_extsyntax in aktmoduleswitches) or
  1058. (not(is_pchar(ld)) and not(m_add_pointer in aktmodeswitches)) then
  1059. CGMessage(type_e_mismatch);
  1060. { Dirty hack, to support multiple firstpasses (PFV) }
  1061. if (resulttype=nil) and
  1062. (rd^.deftype=pointerdef) and
  1063. (ppointerdef(rd)^.pointertype.def^.size>1) then
  1064. begin
  1065. left:=gennode(muln,left,genordinalconstnode(ppointerdef(rd)^.pointertype.def^.size,s32bitdef));
  1066. firstpass(left);
  1067. end;
  1068. end
  1069. else
  1070. CGMessage(type_e_mismatch);
  1071. convdone:=true;
  1072. end
  1073. else
  1074. if (ld^.deftype=pointerdef) or
  1075. is_zero_based_array(ld) then
  1076. begin
  1077. if is_zero_based_array(ld) then
  1078. begin
  1079. resulttype:=new(ppointerdef,init(parraydef(ld)^.elementtype));
  1080. left:=gentypeconvnode(left,resulttype);
  1081. firstpass(left);
  1082. end;
  1083. location.loc:=LOC_REGISTER;
  1084. right:=gentypeconvnode(right,s32bitdef);
  1085. firstpass(right);
  1086. calcregisters(p,1,0,0);
  1087. case treetype of
  1088. addn,subn : begin
  1089. if not(cs_extsyntax in aktmoduleswitches) or
  1090. (not(is_pchar(ld)) and not(m_add_pointer in aktmodeswitches)) then
  1091. CGMessage(type_e_mismatch);
  1092. { Dirty hack, to support multiple firstpasses (PFV) }
  1093. if (resulttype=nil) and
  1094. (ld^.deftype=pointerdef) and
  1095. (ppointerdef(ld)^.pointertype.def^.size>1) then
  1096. begin
  1097. right:=gennode(muln,right,
  1098. genordinalconstnode(ppointerdef(ld)^.pointertype.def^.size,s32bitdef));
  1099. firstpass(right);
  1100. end;
  1101. end;
  1102. else
  1103. CGMessage(type_e_mismatch);
  1104. end;
  1105. convdone:=true;
  1106. end
  1107. else
  1108. if (rd^.deftype=procvardef) and (ld^.deftype=procvardef) and is_equal(rd,ld) then
  1109. begin
  1110. calcregisters(p,1,0,0);
  1111. location.loc:=LOC_REGISTER;
  1112. case treetype of
  1113. equaln,unequaln : ;
  1114. else
  1115. CGMessage(type_e_mismatch);
  1116. end;
  1117. convdone:=true;
  1118. end
  1119. else
  1120. if (ld^.deftype=enumdef) and (rd^.deftype=enumdef) then
  1121. begin
  1122. if not(is_equal(ld,rd)) then
  1123. begin
  1124. right:=gentypeconvnode(right,ld);
  1125. firstpass(right);
  1126. end;
  1127. calcregisters(p,1,0,0);
  1128. case treetype of
  1129. equaln,unequaln,
  1130. ltn,lten,gtn,gten : ;
  1131. else CGMessage(type_e_mismatch);
  1132. end;
  1133. convdone:=true;
  1134. end;
  1135. { the general solution is to convert to 32 bit int }
  1136. if not convdone then
  1137. begin
  1138. { but an int/int gives real/real! }
  1139. if treetype=slashn then
  1140. begin
  1141. CGMessage(type_h_use_div_for_int);
  1142. right:=gentypeconvnode(right,bestrealdef^);
  1143. left:=gentypeconvnode(left,bestrealdef^);
  1144. firstpass(left);
  1145. firstpass(right);
  1146. { maybe we need an integer register to save }
  1147. { a reference }
  1148. if ((left^.location.loc<>LOC_FPU) or
  1149. (right^.location.loc<>LOC_FPU)) and
  1150. (left^.registers32=right^.registers32) then
  1151. calcregisters(p,1,1,0)
  1152. else
  1153. calcregisters(p,0,1,0);
  1154. location.loc:=LOC_FPU;
  1155. end
  1156. else
  1157. begin
  1158. right:=gentypeconvnode(right,s32bitdef);
  1159. left:=gentypeconvnode(left,s32bitdef);
  1160. firstpass(left);
  1161. firstpass(right);
  1162. calcregisters(p,1,0,0);
  1163. location.loc:=LOC_REGISTER;
  1164. end;
  1165. end;
  1166. if codegenerror then
  1167. exit;
  1168. { determines result type for comparions }
  1169. { here the is a problem with multiple passes }
  1170. { example length(s)+1 gets internal 'longint' type first }
  1171. { if it is a arg it is converted to 'LONGINT' }
  1172. { but a second first pass will reset this to 'longint' }
  1173. case treetype of
  1174. ltn,lten,gtn,gten,equaln,unequaln:
  1175. begin
  1176. if (not assigned(resulttype)) or
  1177. (resulttype^.deftype=stringdef) then
  1178. resulttype:=booldef;
  1179. if is_64bitint(left^.resulttype) then
  1180. location.loc:=LOC_JUMP
  1181. else
  1182. location.loc:=LOC_FLAGS;
  1183. end;
  1184. xorn:
  1185. begin
  1186. if not assigned(resulttype) then
  1187. resulttype:=left^.resulttype;
  1188. location.loc:=LOC_REGISTER;
  1189. end;
  1190. addn:
  1191. begin
  1192. if not assigned(resulttype) then
  1193. begin
  1194. { for strings, return is always a 255 char string }
  1195. if is_shortstring(left^.resulttype) then
  1196. resulttype:=cshortstringdef
  1197. else
  1198. resulttype:=left^.resulttype;
  1199. end;
  1200. end;
  1201. {$ifdef cardinalmulfix}
  1202. muln:
  1203. { if we multiply an unsigned with a signed number, the result is signed }
  1204. { in the other cases, the result remains signed or unsigned depending on }
  1205. { the multiplication factors (JM) }
  1206. if (left^.resulttype^.deftype = orddef) and
  1207. (right^.resulttype^.deftype = orddef) and
  1208. is_signed(right^.resulttype) then
  1209. resulttype := right^.resulttype
  1210. else resulttype := left^.resulttype;
  1211. (*
  1212. subn:
  1213. { if we substract a u32bit from a positive constant, the result becomes }
  1214. { s32bit as well (JM) }
  1215. begin
  1216. if (right^.resulttype^.deftype = orddef) and
  1217. (left^.resulttype^.deftype = orddef) and
  1218. (porddef(right^.resulttype)^.typ = u32bit) and
  1219. is_constintnode(left) and
  1220. { (porddef(left^.resulttype)^.typ <> u32bit) and}
  1221. (left^.value > 0) then
  1222. begin
  1223. left := gentypeconvnode(left,u32bitdef);
  1224. firstpass(left);
  1225. end;
  1226. resulttype:=left^.resulttype;
  1227. end;
  1228. *)
  1229. {$endif cardinalmulfix}
  1230. else
  1231. resulttype:=left^.resulttype;
  1232. end;
  1233. end;
  1234. begin
  1235. caddnode:=taddnode;
  1236. end.
  1237. {
  1238. $Log$
  1239. Revision 1.1 2000-08-26 12:24:20 florian
  1240. * initial release
  1241. }