nmat.pas 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. {
  2. Copyright (c) 2000-2005 by Florian Klaempfl
  3. Type checking and register allocation for math nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nmat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node;
  22. type
  23. tmoddivnode = class(tbinopnode)
  24. function pass_1 : tnode;override;
  25. function pass_typecheck:tnode;override;
  26. function simplify(forinline : boolean) : tnode;override;
  27. protected
  28. { override the following if you want to implement }
  29. { parts explicitely in the code generator (JM) }
  30. function use_moddiv64bitint_helper: boolean; virtual;
  31. function first_moddiv64bitint: tnode; virtual;
  32. function firstoptimize: tnode; virtual;
  33. function first_moddivint: tnode; virtual;
  34. end;
  35. tmoddivnodeclass = class of tmoddivnode;
  36. tshlshrnode = class(tbinopnode)
  37. function pass_1 : tnode;override;
  38. function pass_typecheck:tnode;override;
  39. function simplify(forinline : boolean) : tnode;override;
  40. {$if not defined(cpu64bitalu) and not defined(cpuhighleveltarget)}
  41. { override the following if you want to implement }
  42. { parts explicitely in the code generator (CEC)
  43. Should return nil, if everything will be handled
  44. in the code generator
  45. }
  46. function first_shlshr64bitint: tnode; virtual;
  47. {$endif not cpu64bitalu and not cpuhighleveltarget}
  48. end;
  49. tshlshrnodeclass = class of tshlshrnode;
  50. tunaryminusnode = class(tunarynode)
  51. constructor create(expr : tnode);virtual;
  52. function pass_1 : tnode;override;
  53. function pass_typecheck:tnode;override;
  54. function simplify(forinline : boolean) : tnode;override;
  55. end;
  56. tunaryminusnodeclass = class of tunaryminusnode;
  57. tunaryplusnode = class(tunarynode)
  58. constructor create(expr : tnode);virtual;
  59. function pass_1 : tnode;override;
  60. function pass_typecheck:tnode;override;
  61. end;
  62. tunaryplusnodeclass = class of tunaryplusnode;
  63. tnotnode = class(tunarynode)
  64. constructor create(expr : tnode);virtual;
  65. function pass_1 : tnode;override;
  66. function pass_typecheck:tnode;override;
  67. function simplify(forinline : boolean) : tnode;override;
  68. {$ifdef state_tracking}
  69. function track_state_pass(exec_known:boolean):boolean;override;
  70. {$endif}
  71. end;
  72. tnotnodeclass = class of tnotnode;
  73. var
  74. cmoddivnode : tmoddivnodeclass = tmoddivnode;
  75. cshlshrnode : tshlshrnodeclass = tshlshrnode;
  76. cunaryminusnode : tunaryminusnodeclass = tunaryminusnode;
  77. cunaryplusnode : tunaryplusnodeclass = tunaryplusnode;
  78. cnotnode : tnotnodeclass = tnotnode;
  79. implementation
  80. uses
  81. systems,
  82. verbose,globals,cutils,compinnr,
  83. globtype,constexp,
  84. symconst,symtype,symdef,symcpu,
  85. defcmp,defutil,
  86. htypechk,pass_1,
  87. cgbase,
  88. ncon,ncnv,ncal,nadd,nld,nbas,nflw,ninl,
  89. nutils;
  90. {****************************************************************************
  91. TMODDIVNODE
  92. ****************************************************************************}
  93. function tmoddivnode.simplify(forinline : boolean):tnode;
  94. var
  95. rv,lv : tconstexprint;
  96. begin
  97. result:=nil;
  98. if is_constintnode(right) then
  99. begin
  100. rv:=tordconstnode(right).value;
  101. if rv = 1 then
  102. begin
  103. case nodetype of
  104. modn:
  105. result := cordconstnode.create(0,left.resultdef,true);
  106. divn:
  107. result := left.getcopy;
  108. else
  109. internalerror(2019050518);
  110. end;
  111. exit;
  112. end;
  113. if rv = 0 then
  114. begin
  115. { if the node is derived from a generic const parameter
  116. then don't issue an error }
  117. if not (nf_generic_para in flags) then
  118. Message(parser_e_division_by_zero);
  119. { recover }
  120. tordconstnode(right).value := 1;
  121. end;
  122. { the following simplification is also required for correctness
  123. on x86, as its transformation of divisions by constants to
  124. multiplications and shifts does not handle -1 correctly }
  125. if (rv=-1) and
  126. (nodetype=divn) then
  127. begin
  128. result:=cunaryminusnode.create(left);
  129. left:=nil;
  130. exit;
  131. end;
  132. if (nf_isomod in flags) and
  133. (rv<=0) then
  134. begin
  135. Message(cg_e_mod_only_defined_for_pos_quotient);
  136. { recover }
  137. tordconstnode(right).value := 1;
  138. end
  139. else if (rv=-1) and
  140. (nodetype=modn) then
  141. begin
  142. result:=cordconstnode.create(0,left.resultdef,true);
  143. left:=nil;
  144. exit;
  145. end;
  146. end;
  147. if is_constintnode(right) and is_constintnode(left) then
  148. begin
  149. rv:=tordconstnode(right).value;
  150. lv:=tordconstnode(left).value;
  151. case nodetype of
  152. modn:
  153. if nf_isomod in flags then
  154. begin
  155. if lv>=0 then
  156. result:=create_simplified_ord_const(lv mod rv,resultdef,forinline,false)
  157. else
  158. if ((-lv) mod rv)=0 then
  159. result:=create_simplified_ord_const((-lv) mod rv,resultdef,forinline,false)
  160. else
  161. result:=create_simplified_ord_const(rv-((-lv) mod rv),resultdef,forinline,false);
  162. end
  163. else
  164. result:=create_simplified_ord_const(lv mod rv,resultdef,forinline,false);
  165. divn:
  166. result:=create_simplified_ord_const(lv div rv,resultdef,forinline,cs_check_overflow in localswitches);
  167. else
  168. internalerror(2019050519);
  169. end;
  170. end;
  171. end;
  172. function tmoddivnode.use_moddiv64bitint_helper: boolean;
  173. begin
  174. { not with an ifdef around the call to this routine, because e.g. the
  175. Java VM has a signed 64 bit division opcode, but not an unsigned
  176. one }
  177. {$if defined(cpu64bitalu) or defined(cpuhighleveltarget)}
  178. result:=false;
  179. {$else cpu64bitalu or cpuhighleveltarget}
  180. result:=
  181. (left.resultdef.typ=orddef) and
  182. (right.resultdef.typ=orddef) and
  183. { include currency as well }
  184. (is_64bit(left.resultdef) or is_64bit(right.resultdef));
  185. {$endif cpu64bitalu or cpuhighleveltarget}
  186. end;
  187. function tmoddivnode.pass_typecheck:tnode;
  188. var
  189. else_block,
  190. hp,t : tnode;
  191. rd,ld : torddef;
  192. else_statements,
  193. statements : tstatementnode;
  194. result_data : ttempcreatenode;
  195. nd : torddef;
  196. begin
  197. result:=nil;
  198. typecheckpass(left);
  199. typecheckpass(right);
  200. { avoid any problems with type parameters later on }
  201. if is_typeparam(left.resultdef) or is_typeparam(right.resultdef) then
  202. begin
  203. resultdef:=cundefinedtype;
  204. exit;
  205. end;
  206. set_varstate(left,vs_read,[vsf_must_be_valid]);
  207. set_varstate(right,vs_read,[vsf_must_be_valid]);
  208. if codegenerror then
  209. exit;
  210. { tp procvar support }
  211. maybe_call_procvar(left,true);
  212. maybe_call_procvar(right,true);
  213. { allow operator overloading }
  214. t:=self;
  215. if isbinaryoverloaded(t,[]) then
  216. begin
  217. result:=t;
  218. exit;
  219. end;
  220. { we need 2 orddefs always }
  221. if (left.resultdef.typ<>orddef) then
  222. inserttypeconv(left,sinttype);
  223. if (right.resultdef.typ<>orddef) then
  224. inserttypeconv(right,sinttype);
  225. if codegenerror then
  226. exit;
  227. { Try only now to simply constant
  228. as otherwise you might create
  229. tconstnode with return type that are
  230. not compatible with tconst node
  231. as in bug report 21566 PM }
  232. result:=simplify(false);
  233. if assigned(result) then
  234. exit;
  235. rd:=torddef(right.resultdef);
  236. ld:=torddef(left.resultdef);
  237. { if one operand is a cardinal and the other is a positive constant, convert the }
  238. { constant to a cardinal as well so we don't have to do a 64bit division (JM) }
  239. { Do the same for qwords and positive constants as well, otherwise things like }
  240. { "qword mod 10" are evaluated with int64 as result, which is wrong if the }
  241. { "qword" was > high(int64) (JM) }
  242. { Additionally, do the same for cardinal/qwords and other positive types, but }
  243. { always in a way that a smaller type is converted to a bigger type }
  244. { (webtbs/tw8870) }
  245. if (rd.ordtype in [u8bit,u16bit,u32bit,u64bit]) and
  246. ((is_constintnode(left) and
  247. (tordconstnode(left).value >= 0) and
  248. (tordconstnode(left).value <= get_max_value(rd))) or
  249. (not is_signed(ld) and
  250. (rd.size >= ld.size))) then
  251. begin
  252. if rd.size<uinttype.size then
  253. begin
  254. inserttypeconv(left,uinttype);
  255. inserttypeconv(right,uinttype);
  256. end
  257. else
  258. inserttypeconv(left,rd);
  259. resultdef:=right.resultdef;
  260. end
  261. else if (ld.ordtype in [u8bit,u16bit,u32bit,u64bit]) and
  262. ((is_constintnode(right) and
  263. (tordconstnode(right).value >= 0) and
  264. (tordconstnode(right).value <= get_max_value(ld))) or
  265. (not is_signed(rd) and
  266. (ld.size >= rd.size))) then
  267. begin
  268. if ld.size<uinttype.size then
  269. begin
  270. inserttypeconv(left,uinttype);
  271. inserttypeconv(right,uinttype);
  272. end
  273. else
  274. inserttypeconv(right,ld);
  275. resultdef:=left.resultdef;
  276. end
  277. else
  278. { when there is one currency value, everything is done
  279. using currency }
  280. if (ld.ordtype=scurrency) or
  281. (rd.ordtype=scurrency) then
  282. begin
  283. if (ld.ordtype<>scurrency) then
  284. inserttypeconv(left,s64currencytype);
  285. if (rd.ordtype<>scurrency) then
  286. inserttypeconv(right,s64currencytype);
  287. resultdef:=left.resultdef;
  288. end
  289. else
  290. { when there is one 64bit value, everything is done
  291. in 64bit }
  292. if (is_64bitint(left.resultdef) or
  293. is_64bitint(right.resultdef)) then
  294. begin
  295. if is_signed(rd) or is_signed(ld) then
  296. begin
  297. if (ld.ordtype<>s64bit) then
  298. inserttypeconv(left,s64inttype);
  299. if (rd.ordtype<>s64bit) then
  300. inserttypeconv(right,s64inttype);
  301. end
  302. else
  303. begin
  304. if (ld.ordtype<>u64bit) then
  305. inserttypeconv(left,u64inttype);
  306. if (rd.ordtype<>u64bit) then
  307. inserttypeconv(right,u64inttype);
  308. end;
  309. resultdef:=left.resultdef;
  310. end
  311. else
  312. { is there a larger than the native int? }
  313. if is_oversizedint(ld) or is_oversizedint(rd) then
  314. begin
  315. nd:=get_common_intdef(ld,rd,false);
  316. if (ld.ordtype<>nd.ordtype) then
  317. inserttypeconv(left,nd);
  318. if (rd.ordtype<>nd.ordtype) then
  319. inserttypeconv(right,nd);
  320. resultdef:=left.resultdef;
  321. end
  322. else
  323. { when mixing unsigned and signed native ints, convert everything to a larger signed type (JM) }
  324. if (is_nativeuint(rd) and
  325. is_signed(ld)) or
  326. (is_nativeuint(ld) and
  327. is_signed(rd)) then
  328. begin
  329. CGMessage(type_h_mixed_signed_unsigned);
  330. { get a signed int, larger than the native int }
  331. nd:=get_common_intdef(torddef(sinttype),torddef(uinttype),false);
  332. if (ld.ordtype<>nd.ordtype) then
  333. inserttypeconv(left,nd);
  334. if (rd.ordtype<>nd.ordtype) then
  335. inserttypeconv(right,nd);
  336. resultdef:=left.resultdef;
  337. end
  338. else
  339. begin
  340. { Make everything always default singed int }
  341. if not(rd.ordtype in [torddef(sinttype).ordtype,torddef(uinttype).ordtype]) then
  342. inserttypeconv(right,sinttype);
  343. if not(ld.ordtype in [torddef(sinttype).ordtype,torddef(uinttype).ordtype]) then
  344. inserttypeconv(left,sinttype);
  345. resultdef:=right.resultdef;
  346. end;
  347. { when the result is currency we need some extra code for
  348. division. this should not be done when the divn node is
  349. created internally }
  350. if (nodetype=divn) and
  351. not(nf_is_currency in flags) and
  352. is_currency(resultdef) then
  353. begin
  354. hp:=caddnode.create(muln,getcopy,cordconstnode.create(10000,s64currencytype,false));
  355. include(hp.flags,nf_is_currency);
  356. result:=hp;
  357. end;
  358. if (nodetype=modn) and (nf_isomod in flags) then
  359. begin
  360. result:=internalstatements(statements);
  361. else_block:=internalstatements(else_statements);
  362. result_data:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
  363. { right <=0? }
  364. addstatement(statements,cifnode.create_internal(caddnode.create_internal(lten,right.getcopy,cordconstnode.create(0,resultdef,false)),
  365. { then: result:=left mod right }
  366. ccallnode.createintern('fpc_divbyzero',nil),
  367. nil
  368. ));
  369. { prepare else block }
  370. { result:=(-left) mod right }
  371. addstatement(else_statements,cassignmentnode.create(ctemprefnode.create(result_data),cmoddivnode.create(modn,cunaryminusnode.create(left.getcopy),right.getcopy)));
  372. { result<>0? }
  373. addstatement(else_statements,cifnode.create_internal(caddnode.create_internal(unequaln,ctemprefnode.create(result_data),cordconstnode.create(0,resultdef,false)),
  374. { then: result:=right-result }
  375. cassignmentnode.create_internal(ctemprefnode.create(result_data),caddnode.create_internal(subn,right.getcopy,ctemprefnode.create(result_data))),
  376. nil
  377. ));
  378. addstatement(statements,result_data);
  379. { if left>=0 }
  380. addstatement(statements,cifnode.create_internal(caddnode.create_internal(gten,left.getcopy,cordconstnode.create(0,resultdef,false)),
  381. { then: result:=left mod right }
  382. cassignmentnode.create_internal(ctemprefnode.create(result_data),cmoddivnode.create(modn,left.getcopy,right.getcopy)),
  383. { else block }
  384. else_block
  385. ));
  386. addstatement(statements,ctempdeletenode.create_normal_temp(result_data));
  387. addstatement(statements,ctemprefnode.create(result_data));
  388. end;
  389. end;
  390. function tmoddivnode.first_moddivint: tnode;
  391. {$ifdef cpuneedsdivhelper}
  392. var
  393. procname: string[31];
  394. begin
  395. result := nil;
  396. { otherwise create a call to a helper }
  397. if nodetype = divn then
  398. procname := 'fpc_div_'
  399. else
  400. procname := 'fpc_mod_';
  401. { only qword needs the unsigned code, the
  402. signed code is also used for currency }
  403. case torddef(resultdef).ordtype of
  404. u8bit:
  405. procname := procname + 'byte';
  406. s8bit:
  407. procname := procname + 'shortint';
  408. u16bit:
  409. procname := procname + 'word';
  410. s16bit:
  411. procname := procname + 'smallint';
  412. u32bit:
  413. procname := procname + 'dword';
  414. s32bit:
  415. procname := procname + 'longint';
  416. scurrency:
  417. procname := procname + 'currency';
  418. else
  419. internalerror(2015070501);
  420. end;
  421. result := ccallnode.createintern(procname,ccallparanode.create(left,
  422. ccallparanode.create(right,nil)));
  423. left := nil;
  424. right := nil;
  425. firstpass(result);
  426. if result.resultdef.typ<>orddef then
  427. internalerror(2013031701);
  428. if resultdef.typ<>orddef then
  429. internalerror(2013031702);
  430. if torddef(result.resultdef).ordtype <> torddef(resultdef).ordtype then
  431. inserttypeconv(result,resultdef);
  432. end;
  433. {$else cpuneedsdivhelper}
  434. begin
  435. result:=nil;
  436. end;
  437. {$endif cpuneedsdiv32helper}
  438. function tmoddivnode.first_moddiv64bitint: tnode;
  439. var
  440. procname: string[31];
  441. begin
  442. result := nil;
  443. { when currency is used set the result of the
  444. parameters to s64bit, so they are not converted }
  445. if is_currency(resultdef) then
  446. begin
  447. left.resultdef:=s64inttype;
  448. right.resultdef:=s64inttype;
  449. end;
  450. { otherwise create a call to a helper }
  451. if nodetype = divn then
  452. procname := 'fpc_div_'
  453. else
  454. procname := 'fpc_mod_';
  455. { only qword needs the unsigned code, the
  456. signed code is also used for currency }
  457. if is_signed(resultdef) then
  458. procname := procname + 'int64'
  459. else
  460. procname := procname + 'qword';
  461. result := ccallnode.createintern(procname,ccallparanode.create(left,
  462. ccallparanode.create(right,nil)));
  463. left := nil;
  464. right := nil;
  465. firstpass(result);
  466. end;
  467. function tmoddivnode.firstoptimize: tnode;
  468. var
  469. power,shiftval : longint;
  470. statements : tstatementnode;
  471. temp,resulttemp : ttempcreatenode;
  472. masknode : tnode;
  473. invertsign: Boolean;
  474. begin
  475. result := nil;
  476. { divide/mod a number by a constant which is a power of 2? }
  477. if (right.nodetype = ordconstn) and
  478. isabspowerof2(tordconstnode(right).value,power) and
  479. {$if defined(cpu64bitalu) or defined(cpuhighleveltarget)}
  480. { for 64 bit, we leave the optimization to the cg }
  481. (not is_signed(resultdef)) then
  482. {$else cpu64bitalu or cpuhighleveltarget}
  483. (((nodetype=divn) and is_oversizedord(resultdef)) or
  484. (nodetype=modn) or
  485. not is_signed(resultdef)) then
  486. {$endif cpu64bitalu or cpuhighleveltarget}
  487. begin
  488. if nodetype=divn then
  489. begin
  490. if is_signed(resultdef) then
  491. begin
  492. invertsign:=tordconstnode(right).value<0;
  493. if is_64bitint(left.resultdef) then
  494. if not (cs_opt_size in current_settings.optimizerswitches) then
  495. shiftval:=63
  496. else
  497. { the shift code is a lot bigger than the call to }
  498. { the divide helper }
  499. exit
  500. else
  501. shiftval:=left.resultdef.size*8-1;
  502. result:=internalstatements(statements);
  503. temp:=ctempcreatenode.create(left.resultdef,left.resultdef.size,tt_persistent,true);
  504. resulttemp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
  505. addstatement(statements,resulttemp);
  506. addstatement(statements,temp);
  507. addstatement(statements,cassignmentnode.create(ctemprefnode.create(temp),
  508. left));
  509. left:=nil;
  510. { masknode is (sar(temp,shiftval) and ((1 shl power)-1))
  511. for power=1 (i.e. division by 2), masknode is simply (temp shr shiftval)}
  512. if power=1 then
  513. masknode:=
  514. cshlshrnode.create(shrn,
  515. ctemprefnode.create(temp),
  516. cordconstnode.create(shiftval,u8inttype,false)
  517. )
  518. else
  519. masknode:=
  520. caddnode.create(andn,
  521. cinlinenode.create(in_sar_x_y,false,
  522. ccallparanode.create(cordconstnode.create(shiftval,u8inttype,false),
  523. ccallparanode.create(ctemprefnode.create(temp),nil))
  524. ),
  525. cordconstnode.create(tcgint((qword(1) shl power)-1),
  526. right.resultdef,false)
  527. );
  528. if invertsign then
  529. addstatement(statements,cassignmentnode.create(ctemprefnode.create(resulttemp),
  530. cunaryminusnode.create(
  531. cinlinenode.create(in_sar_x_y,false,
  532. ccallparanode.create(cordconstnode.create(power,u8inttype,false),
  533. ccallparanode.create(caddnode.create(addn,ctemprefnode.create(temp),
  534. masknode),nil
  535. )))))
  536. )
  537. else
  538. addstatement(statements,cassignmentnode.create(ctemprefnode.create(resulttemp),
  539. cinlinenode.create(in_sar_x_y,false,
  540. ccallparanode.create(cordconstnode.create(power,u8inttype,false),
  541. ccallparanode.create(caddnode.create(addn,ctemprefnode.create(temp),
  542. masknode),nil
  543. ))))
  544. );
  545. addstatement(statements,ctempdeletenode.create(temp));
  546. addstatement(statements,ctempdeletenode.create_normal_temp(resulttemp));
  547. addstatement(statements,ctemprefnode.create(resulttemp));
  548. right.Free;
  549. end
  550. else
  551. begin
  552. tordconstnode(right).value:=power;
  553. result:=cshlshrnode.create(shrn,left,right)
  554. end;
  555. end
  556. else if is_signed(resultdef) then { signed modulus }
  557. begin
  558. if (cs_opt_size in current_settings.optimizerswitches) then
  559. exit;
  560. shiftval:=left.resultdef.size*8-1;
  561. tordconstnode(right).value.uvalue:=qword((qword(1) shl power)-1);
  562. result:=internalstatements(statements);
  563. temp:=ctempcreatenode.create(left.resultdef,left.resultdef.size,tt_persistent,true);
  564. resulttemp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
  565. addstatement(statements,resulttemp);
  566. addstatement(statements,temp);
  567. addstatement(statements,cassignmentnode.create(ctemprefnode.create(temp),left));
  568. { mask:=sar(left,sizeof(left)*8-1) and ((1 shl power)-1); }
  569. if power=1 then
  570. masknode:=
  571. cshlshrnode.create(shrn,
  572. ctemprefnode.create(temp),
  573. cordconstnode.create(shiftval,u8inttype,false)
  574. )
  575. else
  576. masknode:=
  577. caddnode.create(andn,
  578. cinlinenode.create(in_sar_x_y,false,
  579. ccallparanode.create(cordconstnode.create(shiftval,u8inttype,false),
  580. ccallparanode.create(ctemprefnode.create(temp),nil))
  581. ),
  582. cordconstnode.create(tcgint((qword(1) shl power)-1),
  583. right.resultdef,false)
  584. );
  585. addstatement(statements,cassignmentnode.create(ctemprefnode.create(resulttemp),masknode));
  586. { result:=((left+mask) and right)-mask; }
  587. addstatement(statements,cassignmentnode.create(ctemprefnode.create(resulttemp),
  588. caddnode.create(subn,
  589. caddnode.create(andn,
  590. right,
  591. caddnode.create(addn,
  592. ctemprefnode.create(temp),
  593. ctemprefnode.create(resulttemp))),
  594. ctemprefnode.create(resulttemp))
  595. ));
  596. addstatement(statements,ctempdeletenode.create(temp));
  597. addstatement(statements,ctempdeletenode.create_normal_temp(resulttemp));
  598. addstatement(statements,ctemprefnode.create(resulttemp));
  599. end
  600. else
  601. begin
  602. tordconstnode(right).value.uvalue:=qword((qword(1) shl power)-1);
  603. result := caddnode.create(andn,left,right);
  604. end;
  605. { left and right are reused }
  606. left := nil;
  607. right := nil;
  608. firstpass(result);
  609. exit;
  610. end;
  611. end;
  612. function tmoddivnode.pass_1 : tnode;
  613. begin
  614. result:=nil;
  615. firstpass(left);
  616. firstpass(right);
  617. if codegenerror then
  618. exit;
  619. { Try to optimize mod/div }
  620. result := firstoptimize;
  621. if assigned(result) then
  622. exit;
  623. { 64bit }
  624. if use_moddiv64bitint_helper then
  625. begin
  626. result := first_moddiv64bitint;
  627. if assigned(result) then
  628. exit;
  629. expectloc:=LOC_REGISTER;
  630. end
  631. else
  632. begin
  633. result := first_moddivint;
  634. if assigned(result) then
  635. exit;
  636. end;
  637. expectloc:=LOC_REGISTER;
  638. end;
  639. {****************************************************************************
  640. TSHLSHRNODE
  641. ****************************************************************************}
  642. function tshlshrnode.simplify(forinline : boolean):tnode;
  643. var
  644. lvalue, rvalue, mask : Tconstexprint;
  645. rangedef: tdef;
  646. size: longint;
  647. begin
  648. result:=nil;
  649. { constant folding }
  650. if is_constintnode(right) then
  651. begin
  652. if forinline then
  653. begin
  654. case resultdef.size of
  655. 1,2,4:
  656. rvalue:=tordconstnode(right).value and byte($1f);
  657. 8:
  658. rvalue:=tordconstnode(right).value and byte($3f);
  659. else
  660. internalerror(2013122302);
  661. end;
  662. end
  663. else
  664. rvalue:=tordconstnode(right).value;
  665. if is_constintnode(left) then
  666. begin
  667. lvalue:=tordconstnode(left).value;
  668. getrangedefmasksize(resultdef, rangedef, mask, size);
  669. { shr is an unsigned operation, so cut off upper bits }
  670. if forinline then
  671. lvalue:=lvalue and mask;
  672. case nodetype of
  673. shrn:
  674. lvalue:=lvalue shr rvalue;
  675. shln:
  676. lvalue:=lvalue shl rvalue;
  677. else
  678. internalerror(2019050517);
  679. end;
  680. { discard shifted-out bits (shl never triggers overflow/range errors) }
  681. if forinline and
  682. (nodetype=shln) then
  683. lvalue:=lvalue and mask;
  684. result:=create_simplified_ord_const(lvalue,resultdef,forinline,false);
  685. end
  686. else if rvalue=0 then
  687. begin
  688. result:=left;
  689. left:=nil;
  690. end;
  691. end
  692. else if is_constintnode(left) then
  693. begin
  694. lvalue:=tordconstnode(left).value;
  695. if forinline then
  696. begin
  697. getrangedefmasksize(resultdef, rangedef, mask, size);
  698. lvalue:=lvalue and mask;
  699. end;
  700. { '0 shl x' and '0 shr x' are 0 }
  701. if (lvalue=0) and
  702. ((cs_opt_level4 in current_settings.optimizerswitches) or
  703. not might_have_sideeffects(right)) then
  704. result:=cordconstnode.create(0,resultdef,true);
  705. end;
  706. end;
  707. function tshlshrnode.pass_typecheck:tnode;
  708. var
  709. t : tnode;
  710. begin
  711. result:=nil;
  712. typecheckpass(left);
  713. typecheckpass(right);
  714. { avoid any problems with type parameters later on }
  715. if is_typeparam(left.resultdef) or is_typeparam(right.resultdef) then
  716. begin
  717. resultdef:=cundefinedtype;
  718. exit;
  719. end;
  720. set_varstate(right,vs_read,[vsf_must_be_valid]);
  721. set_varstate(left,vs_read,[vsf_must_be_valid]);
  722. if codegenerror then
  723. exit;
  724. { tp procvar support }
  725. maybe_call_procvar(left,true);
  726. maybe_call_procvar(right,true);
  727. { allow operator overloading }
  728. t:=self;
  729. if isbinaryoverloaded(t,[]) then
  730. begin
  731. result:=t;
  732. exit;
  733. end;
  734. {$ifdef SUPPORT_MMX}
  735. if (cs_mmx in current_settings.localswitches) and
  736. is_mmx_able_array(left.resultdef) and
  737. ((is_mmx_able_array(right.resultdef) and
  738. equal_defs(left.resultdef,right.resultdef)
  739. ) or is_constintnode(right)) then
  740. begin
  741. if not(mmx_type(left.resultdef) in [mmxu16bit,mmxs16bit,mmxfixed16,mmxu32bit,mmxs32bit,mmxu64bit,mmxs64bit]) then
  742. CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),left.resultdef.typename,right.resultdef.typename);
  743. if not(is_mmx_able_array(right.resultdef)) then
  744. inserttypeconv(right,sinttype);
  745. end
  746. else
  747. {$endif SUPPORT_MMX}
  748. begin
  749. { calculations for ordinals < 32 bit have to be done in
  750. 32 bit for backwards compatibility. That way 'shl 33' is
  751. the same as 'shl 1'. It's ugly but compatible with delphi/tp/gcc }
  752. if (not is_64bit(left.resultdef)) and
  753. (torddef(left.resultdef).ordtype<>u32bit) then
  754. begin
  755. { keep singness of orignal type }
  756. if is_signed(left.resultdef) then
  757. begin
  758. {$if defined(cpu64bitalu) or defined(cpu32bitalu)}
  759. inserttypeconv(left,s32inttype)
  760. {$elseif defined(cpu16bitalu) or defined(cpu8bitalu)}
  761. inserttypeconv(left,get_common_intdef(torddef(left.resultdef),torddef(sinttype),true));
  762. {$else}
  763. internalerror(2013031301);
  764. {$endif}
  765. end
  766. else
  767. begin
  768. {$if defined(cpu64bitalu) or defined(cpu32bitalu)}
  769. inserttypeconv(left,u32inttype);
  770. {$elseif defined(cpu16bitalu) or defined(cpu8bitalu)}
  771. inserttypeconv(left,get_common_intdef(torddef(left.resultdef),torddef(uinttype),true));
  772. {$else}
  773. internalerror(2013031302);
  774. {$endif}
  775. end
  776. end;
  777. inserttypeconv(right,sinttype);
  778. end;
  779. resultdef:=left.resultdef;
  780. result:=simplify(false);
  781. if assigned(result) then
  782. exit;
  783. end;
  784. {$if not defined(cpu64bitalu) and not defined(cpuhighleveltarget)}
  785. function tshlshrnode.first_shlshr64bitint: tnode;
  786. var
  787. procname: string[31];
  788. begin
  789. result := nil;
  790. { Normally already done below, but called again,
  791. just in case it is called directly }
  792. firstpass(left);
  793. { otherwise create a call to a helper }
  794. if is_signed(left.resultdef) then
  795. procname:='int64'
  796. else
  797. procname:='qword';
  798. if nodetype = shln then
  799. procname := 'fpc_shl_'+procname
  800. else
  801. procname := 'fpc_shr_'+procname;
  802. { this order of parameters works at least for the arm,
  803. however it should work for any calling conventions (FK) }
  804. result := ccallnode.createintern(procname,ccallparanode.create(right,
  805. ccallparanode.create(left,nil)));
  806. left := nil;
  807. right := nil;
  808. firstpass(result);
  809. end;
  810. {$endif not cpu64bitalu and not cpuhighleveltarget}
  811. function tshlshrnode.pass_1 : tnode;
  812. begin
  813. result:=nil;
  814. firstpass(left);
  815. firstpass(right);
  816. if codegenerror then
  817. exit;
  818. expectloc:=LOC_REGISTER;
  819. {$if not defined(cpu64bitalu) and not defined(cpuhighleveltarget)}
  820. { 64 bit ints have their own shift handling }
  821. if is_64bit(left.resultdef) then
  822. result := first_shlshr64bitint;
  823. {$endif not cpu64bitalu and not cpuhighleveltarget}
  824. end;
  825. {****************************************************************************
  826. TUNARYMINUSNODE
  827. ****************************************************************************}
  828. constructor tunaryminusnode.create(expr : tnode);
  829. begin
  830. inherited create(unaryminusn,expr);
  831. end;
  832. function tunaryminusnode.simplify(forinline : boolean):tnode;
  833. begin
  834. result:=nil;
  835. { constant folding }
  836. if is_constintnode(left) then
  837. begin
  838. result:=create_simplified_ord_const(-tordconstnode(left).value,resultdef,forinline,cs_check_overflow in localswitches);
  839. exit;
  840. end;
  841. if is_constrealnode(left) then
  842. begin
  843. trealconstnode(left).value_real:=-trealconstnode(left).value_real;
  844. { Avoid integer overflow on x86_64 CPU for currency value }
  845. { i386 uses fildll/fchs/fistll instructions which never seem
  846. to raise any coprocessor flags .. }
  847. {$push}{$Q-}
  848. trealconstnode(left).value_currency:=-trealconstnode(left).value_currency;
  849. result:=left;
  850. {$pop}
  851. left:=nil;
  852. exit;
  853. end;
  854. end;
  855. function tunaryminusnode.pass_typecheck : tnode;
  856. var
  857. t : tnode;
  858. begin
  859. result:=nil;
  860. typecheckpass(left);
  861. { avoid any problems with type parameters later on }
  862. if is_typeparam(left.resultdef) then
  863. begin
  864. resultdef:=cundefinedtype;
  865. exit;
  866. end;
  867. set_varstate(left,vs_read,[vsf_must_be_valid]);
  868. if codegenerror then
  869. exit;
  870. result:=simplify(false);
  871. if assigned(result) then
  872. exit;
  873. resultdef:=left.resultdef;
  874. if is_currency(left.resultdef) then
  875. begin
  876. end
  877. else if left.resultdef.typ=floatdef then
  878. begin
  879. if not(tfloatdef(left.resultdef).floattype in [s64comp,s64currency]) and
  880. (cs_excessprecision in current_settings.localswitches) then
  881. begin
  882. inserttypeconv(left,pbestrealtype^);
  883. resultdef:=left.resultdef
  884. end;
  885. end
  886. {$ifdef SUPPORT_MMX}
  887. else if (cs_mmx in current_settings.localswitches) and
  888. is_mmx_able_array(left.resultdef) then
  889. begin
  890. { if saturation is on, left.resultdef isn't
  891. "mmx able" (FK)
  892. if (cs_mmx_saturation in current_settings.localswitches^) and
  893. (torddef(tarraydef(resultdef).definition).typ in
  894. [s32bit,u32bit]) then
  895. CGMessage(type_e_mismatch);
  896. }
  897. end
  898. {$endif SUPPORT_MMX}
  899. else if is_oversizedord(left.resultdef) then
  900. begin
  901. if is_64bit(left.resultdef) then
  902. inserttypeconv(left,s64inttype)
  903. else if is_32bit(left.resultdef) then
  904. inserttypeconv(left,s32inttype)
  905. else if is_16bit(left.resultdef) then
  906. inserttypeconv(left,s16inttype)
  907. else
  908. internalerror(2013040701);
  909. resultdef:=left.resultdef;
  910. end
  911. else if (left.resultdef.typ=orddef) then
  912. begin
  913. inserttypeconv(left,sinttype);
  914. resultdef:=left.resultdef
  915. end
  916. else
  917. begin
  918. { allow operator overloading }
  919. t:=self;
  920. if isunaryoverloaded(t,[]) then
  921. begin
  922. result:=t;
  923. exit;
  924. end;
  925. CGMessage(type_e_mismatch);
  926. end;
  927. end;
  928. { generic code }
  929. { overridden by: }
  930. { i386 }
  931. function tunaryminusnode.pass_1 : tnode;
  932. var
  933. procname: string[31];
  934. begin
  935. result:=nil;
  936. firstpass(left);
  937. if codegenerror then
  938. exit;
  939. if (cs_fp_emulation in current_settings.moduleswitches) and (left.resultdef.typ=floatdef) then
  940. begin
  941. if not(target_info.system in systems_wince) then
  942. begin
  943. expectloc:=LOC_REGISTER;
  944. exit;
  945. end
  946. else
  947. begin
  948. case tfloatdef(resultdef).floattype of
  949. s32real:
  950. procname:='negs';
  951. s64real:
  952. procname:='negd';
  953. {!!! not yet implemented
  954. s128real:
  955. }
  956. else
  957. internalerror(2005082802);
  958. end;
  959. result:=ccallnode.createintern(procname,ccallparanode.create(left,nil));
  960. end;
  961. left:=nil;
  962. end
  963. else
  964. begin
  965. if (left.resultdef.typ=floatdef) then
  966. expectloc:=LOC_FPUREGISTER
  967. {$ifdef SUPPORT_MMX}
  968. else if (cs_mmx in current_settings.localswitches) and
  969. is_mmx_able_array(left.resultdef) then
  970. expectloc:=LOC_MMXREGISTER
  971. {$endif SUPPORT_MMX}
  972. else if (left.resultdef.typ=orddef) then
  973. expectloc:=LOC_REGISTER;
  974. end;
  975. end;
  976. {****************************************************************************
  977. TUNARYPLUSNODE
  978. ****************************************************************************}
  979. constructor tunaryplusnode.create(expr: tnode);
  980. begin
  981. inherited create(unaryplusn,expr);
  982. end;
  983. function tunaryplusnode.pass_1: tnode;
  984. begin
  985. result:=nil;
  986. { can never happen because all the conversions happen
  987. in pass_typecheck }
  988. internalerror(201012250);
  989. end;
  990. function tunaryplusnode.pass_typecheck: tnode;
  991. var
  992. t:tnode;
  993. begin
  994. result:=nil;
  995. typecheckpass(left);
  996. { avoid any problems with type parameters later on }
  997. if is_typeparam(left.resultdef) then
  998. begin
  999. resultdef:=cundefinedtype;
  1000. exit;
  1001. end;
  1002. set_varstate(left,vs_read,[vsf_must_be_valid]);
  1003. if codegenerror then
  1004. exit;
  1005. if is_constintnode(left) or
  1006. is_constrealnode(left) or
  1007. (left.resultdef.typ=floatdef) or
  1008. is_currency(left.resultdef)
  1009. {$ifdef SUPPORT_MMX}
  1010. or ((cs_mmx in current_settings.localswitches) and
  1011. is_mmx_able_array(left.resultdef))
  1012. {$endif SUPPORT_MMX}
  1013. then
  1014. begin
  1015. result:=left;
  1016. left:=nil;
  1017. end
  1018. else if is_oversizedord(left.resultdef) then
  1019. begin
  1020. if is_64bit(left.resultdef) then
  1021. inserttypeconv(left,s64inttype)
  1022. else if is_32bit(left.resultdef) then
  1023. inserttypeconv(left,s32inttype)
  1024. else if is_16bit(left.resultdef) then
  1025. inserttypeconv(left,s16inttype)
  1026. else
  1027. internalerror(2013040702);
  1028. result:=left;
  1029. left:=nil;
  1030. end
  1031. else if (left.resultdef.typ=orddef) then
  1032. begin
  1033. inserttypeconv(left,sinttype);
  1034. result:=left;
  1035. left:=nil;
  1036. end
  1037. else
  1038. begin
  1039. { allow operator overloading }
  1040. t:=self;
  1041. if isunaryoverloaded(t,[]) then
  1042. begin
  1043. result:=t;
  1044. exit;
  1045. end;
  1046. CGMessage(type_e_mismatch);
  1047. end;
  1048. end;
  1049. {****************************************************************************
  1050. TNOTNODE
  1051. ****************************************************************************}
  1052. const
  1053. boolean_reverse:array[ltn..unequaln] of Tnodetype=(
  1054. gten,gtn,lten,ltn,unequaln,equaln
  1055. );
  1056. constructor tnotnode.create(expr : tnode);
  1057. begin
  1058. inherited create(notn,expr);
  1059. end;
  1060. function tnotnode.simplify(forinline : boolean):tnode;
  1061. var
  1062. v : tconstexprint;
  1063. t : tnode;
  1064. def : tdef;
  1065. begin
  1066. result:=nil;
  1067. { Try optmimizing ourself away }
  1068. if left.nodetype=notn then
  1069. begin
  1070. { Double not. Remove both }
  1071. result:=Tnotnode(left).left;
  1072. tnotnode(left).left:=nil;
  1073. exit;
  1074. end;
  1075. if (left.nodetype in [ltn,lten,equaln,unequaln,gtn,gten]) then
  1076. begin
  1077. { Not of boolean expression. Turn around the operator and remove
  1078. the not. This is not allowed for sets with the gten/lten,
  1079. because there is no ltn/gtn support }
  1080. if (taddnode(left).left.resultdef.typ<>setdef) or
  1081. (left.nodetype in [equaln,unequaln]) then
  1082. begin
  1083. result:=left;
  1084. left.nodetype:=boolean_reverse[left.nodetype];
  1085. left:=nil;
  1086. exit;
  1087. end;
  1088. end;
  1089. { constant folding }
  1090. if (left.nodetype=ordconstn) and
  1091. (left.resultdef.typ=orddef) then
  1092. begin
  1093. v:=tordconstnode(left).value;
  1094. def:=left.resultdef;
  1095. if not calc_not_ordvalue(v,def) then
  1096. CGMessage(type_e_mismatch);
  1097. { not-nodes are not range checked by the code generator -> also
  1098. don't range check while inlining; the resultdef is a bit tricky
  1099. though: the node's resultdef gets changed in most cases compared
  1100. to left, but the not-operation itself is caried out in the code
  1101. generator using the size of left
  1102. }
  1103. if not(forinline) then
  1104. t:=cordconstnode.create(v,def,false)
  1105. else
  1106. begin
  1107. { cut off the value if necessary }
  1108. t:=cordconstnode.create(v,left.resultdef,false);
  1109. { now convert to node's resultdef }
  1110. inserttypeconv_explicit(t,def);
  1111. end;
  1112. result:=t;
  1113. exit;
  1114. end;
  1115. end;
  1116. function tnotnode.pass_typecheck : tnode;
  1117. var
  1118. t : tnode;
  1119. begin
  1120. result:=nil;
  1121. typecheckpass(left);
  1122. { avoid any problems with type parameters later on }
  1123. if is_typeparam(left.resultdef) then
  1124. begin
  1125. resultdef:=cundefinedtype;
  1126. exit;
  1127. end;
  1128. set_varstate(left,vs_read,[vsf_must_be_valid]);
  1129. if codegenerror then
  1130. exit;
  1131. { tp procvar support }
  1132. maybe_call_procvar(left,true);
  1133. resultdef:=left.resultdef;
  1134. result:=simplify(false);
  1135. if assigned(result) then
  1136. exit;
  1137. if is_boolean(resultdef) then
  1138. begin
  1139. end
  1140. else
  1141. {$ifdef SUPPORT_MMX}
  1142. if (cs_mmx in current_settings.localswitches) and
  1143. is_mmx_able_array(left.resultdef) then
  1144. begin
  1145. end
  1146. else
  1147. {$endif SUPPORT_MMX}
  1148. {$ifndef cpu64bitaddr}
  1149. if is_64bitint(left.resultdef) then
  1150. begin
  1151. end
  1152. else
  1153. {$endif not cpu64bitaddr}
  1154. if is_integer(left.resultdef) then
  1155. begin
  1156. end
  1157. else
  1158. begin
  1159. { allow operator overloading }
  1160. t:=self;
  1161. if isunaryoverloaded(t,[]) then
  1162. begin
  1163. result:=t;
  1164. exit;
  1165. end;
  1166. CGMessage(type_e_mismatch);
  1167. end;
  1168. end;
  1169. function tnotnode.pass_1 : tnode;
  1170. begin
  1171. result:=nil;
  1172. firstpass(left);
  1173. if codegenerror then
  1174. exit;
  1175. expectloc:=left.expectloc;
  1176. if is_boolean(resultdef) then
  1177. begin
  1178. if (expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
  1179. expectloc:=LOC_REGISTER;
  1180. { xtensa has boolean registers which are treateed as flags but they
  1181. are not used for boolean expressions }
  1182. {$if defined(cpuflags) and not(defined(xtensa))}
  1183. if left.expectloc<>LOC_JUMP then
  1184. expectloc:=LOC_FLAGS;
  1185. {$endif defined(cpuflags) and not(defined(xtensa)}
  1186. end
  1187. else
  1188. {$ifdef SUPPORT_MMX}
  1189. if (cs_mmx in current_settings.localswitches) and
  1190. is_mmx_able_array(left.resultdef) then
  1191. expectloc:=LOC_MMXREGISTER
  1192. else
  1193. {$endif SUPPORT_MMX}
  1194. {$if not defined(cpu64bitalu) and not defined(cpuhighleveltarget)}
  1195. if is_64bit(left.resultdef) then
  1196. begin
  1197. if (expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
  1198. expectloc:=LOC_REGISTER;
  1199. end
  1200. else
  1201. {$endif not cpu64bitalu and not cpuhighleveltarget}
  1202. if is_integer(left.resultdef) then
  1203. expectloc:=LOC_REGISTER;
  1204. end;
  1205. {$ifdef state_tracking}
  1206. function Tnotnode.track_state_pass(exec_known:boolean):boolean;
  1207. begin
  1208. track_state_pass:=true;
  1209. if left.track_state_pass(exec_known) then
  1210. begin
  1211. left.resultdef:=nil;
  1212. do_typecheckpass(left);
  1213. end;
  1214. end;
  1215. {$endif}
  1216. end.