cg386inl.pas 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 inline 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 cg386inl;
  19. interface
  20. uses
  21. tree;
  22. procedure secondinline(var p : ptree);
  23. implementation
  24. uses
  25. globtype,systems,
  26. cobjects,verbose,globals,files,
  27. symtable,aasm,types,
  28. hcodegen,temp_gen,pass_2,
  29. i386,cgai386,tgeni386,cg386ld,cg386cal;
  30. {*****************************************************************************
  31. Helpers
  32. *****************************************************************************}
  33. { reverts the parameter list }
  34. var nb_para : integer;
  35. function reversparameter(p : ptree) : ptree;
  36. var
  37. hp1,hp2 : ptree;
  38. begin
  39. hp1:=nil;
  40. nb_para := 0;
  41. while assigned(p) do
  42. begin
  43. { pull out }
  44. hp2:=p;
  45. p:=p^.right;
  46. inc(nb_para);
  47. { pull in }
  48. hp2^.right:=hp1;
  49. hp1:=hp2;
  50. end;
  51. reversparameter:=hp1;
  52. end;
  53. {*****************************************************************************
  54. SecondInLine
  55. *****************************************************************************}
  56. procedure secondinline(var p : ptree);
  57. const
  58. { tfloattype = (f32bit,s32real,s64real,s80real,s64bit); }
  59. float_name: array[tfloattype] of string[8]=
  60. ('FIXED','SINGLE','REAL','EXTENDED','COMP','FIXED16');
  61. incdecop:array[in_inc_x..in_dec_x] of tasmop=(A_INC,A_DEC);
  62. addsubop:array[in_inc_x..in_dec_x] of tasmop=(A_ADD,A_SUB);
  63. var
  64. aktfile : treference;
  65. ft : tfiletype;
  66. opsize : topsize;
  67. asmop : tasmop;
  68. pushed : tpushed;
  69. {inc/dec}
  70. addconstant : boolean;
  71. addvalue : longint;
  72. procedure handlereadwrite(doread,doln : boolean);
  73. { produces code for READ(LN) and WRITE(LN) }
  74. procedure loadstream;
  75. const
  76. io:array[0..1] of string[7]=('_OUTPUT','_INPUT');
  77. var
  78. r : preference;
  79. begin
  80. new(r);
  81. reset_reference(r^);
  82. r^.symbol:=stringdup('U_'+upper(target_info.system_unit)+io[byte(doread)]);
  83. concat_external(r^.symbol^,EXT_NEAR);
  84. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,r,R_EDI)))
  85. end;
  86. var
  87. node,hp : ptree;
  88. typedtyp,
  89. pararesult : pdef;
  90. has_length : boolean;
  91. dummycoll : tdefcoll;
  92. iolabel : plabel;
  93. npara : longint;
  94. begin
  95. { I/O check }
  96. if (cs_check_io in aktlocalswitches) and
  97. ((aktprocsym^.definition^.options and poiocheck)=0) then
  98. begin
  99. getlabel(iolabel);
  100. emitl(A_LABEL,iolabel);
  101. end
  102. else
  103. iolabel:=nil;
  104. { for write of real with the length specified }
  105. has_length:=false;
  106. hp:=nil;
  107. { reserve temporary pointer to data variable }
  108. aktfile.symbol:=nil;
  109. gettempofsizereference(4,aktfile);
  110. { first state text data }
  111. ft:=ft_text;
  112. { and state a parameter ? }
  113. if p^.left=nil then
  114. begin
  115. { the following instructions are for "writeln;" }
  116. loadstream;
  117. { save @aktfile in temporary variable }
  118. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,newreference(aktfile))));
  119. end
  120. else
  121. begin
  122. { revers paramters }
  123. node:=reversparameter(p^.left);
  124. p^.left := node;
  125. npara := nb_para;
  126. { calculate data variable }
  127. { is first parameter a file type ? }
  128. if node^.left^.resulttype^.deftype=filedef then
  129. begin
  130. ft:=pfiledef(node^.left^.resulttype)^.filetype;
  131. if ft=ft_typed then
  132. typedtyp:=pfiledef(node^.left^.resulttype)^.typed_as;
  133. secondpass(node^.left);
  134. if codegenerror then
  135. exit;
  136. { save reference in temporary variables }
  137. if node^.left^.location.loc<>LOC_REFERENCE then
  138. begin
  139. CGMessage(cg_e_illegal_expression);
  140. exit;
  141. end;
  142. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,newreference(node^.left^.location.reference),R_EDI)));
  143. { skip to the next parameter }
  144. node:=node^.right;
  145. end
  146. else
  147. begin
  148. { load stdin/stdout stream }
  149. loadstream;
  150. end;
  151. { save @aktfile in temporary variable }
  152. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,newreference(aktfile))));
  153. if doread then
  154. { parameter by READ gives call by reference }
  155. dummycoll.paratyp:=vs_var
  156. { an WRITE Call by "Const" }
  157. else
  158. dummycoll.paratyp:=vs_const;
  159. { because of secondcallparan, which otherwise attaches }
  160. if ft=ft_typed then
  161. { this is to avoid copy of simple const parameters }
  162. dummycoll.data:=new(pformaldef,init)
  163. else
  164. { I think, this isn't a good solution (FK) }
  165. dummycoll.data:=nil;
  166. while assigned(node) do
  167. begin
  168. pushusedregisters(pushed,$ff);
  169. hp:=node;
  170. node:=node^.right;
  171. hp^.right:=nil;
  172. if hp^.is_colon_para then
  173. CGMessage(parser_e_illegal_colon_qualifier);
  174. if ft=ft_typed then
  175. never_copy_const_param:=true;
  176. { reset data type }
  177. dummycoll.data:=nil;
  178. { support openstring calling for readln(shortstring) }
  179. if doread and (is_shortstring(hp^.resulttype)) then
  180. dummycoll.data:=openshortstringdef;
  181. secondcallparan(hp,@dummycoll,false,false,0);
  182. if ft=ft_typed then
  183. never_copy_const_param:=false;
  184. hp^.right:=node;
  185. if codegenerror then
  186. exit;
  187. emit_push_mem(aktfile);
  188. if (ft=ft_typed) then
  189. begin
  190. { OK let's try this }
  191. { first we must only allow the right type }
  192. { we have to call blockread or blockwrite }
  193. { but the real problem is that }
  194. { reset and rewrite should have set }
  195. { the type size }
  196. { as recordsize for that file !!!! }
  197. { how can we make that }
  198. { I think that is only possible by adding }
  199. { reset and rewrite to the inline list a call }
  200. { allways read only one record by element }
  201. push_int(typedtyp^.size);
  202. if doread then
  203. emitcall('FPC_TYPED_READ',true)
  204. else
  205. emitcall('FPC_TYPED_WRITE',true);
  206. end
  207. else
  208. begin
  209. { save current position }
  210. pararesult:=hp^.left^.resulttype;
  211. { handle possible field width }
  212. { of course only for write(ln) }
  213. if not doread then
  214. begin
  215. { handle total width parameter }
  216. if assigned(node) and node^.is_colon_para then
  217. begin
  218. hp:=node;
  219. node:=node^.right;
  220. hp^.right:=nil;
  221. secondcallparan(hp,@dummycoll,false,false,0);
  222. hp^.right:=node;
  223. if codegenerror then
  224. exit;
  225. has_length:=true;
  226. end
  227. else
  228. if pararesult^.deftype<>floatdef then
  229. push_int(0)
  230. else
  231. push_int(-32767);
  232. { a second colon para for a float ? }
  233. if assigned(node) and node^.is_colon_para then
  234. begin
  235. hp:=node;
  236. node:=node^.right;
  237. hp^.right:=nil;
  238. secondcallparan(hp,@dummycoll,false,false,0);
  239. hp^.right:=node;
  240. if pararesult^.deftype<>floatdef then
  241. CGMessage(parser_e_illegal_colon_qualifier);
  242. if codegenerror then
  243. exit;
  244. end
  245. else
  246. begin
  247. if pararesult^.deftype=floatdef then
  248. push_int(-1);
  249. end
  250. end;
  251. case pararesult^.deftype of
  252. stringdef : begin
  253. if doread then
  254. begin
  255. { push maximum string length }
  256. case pstringdef(pararesult)^.string_typ of
  257. st_shortstring:
  258. emitcall ('FPC_READ_TEXT_STRING',true);
  259. st_ansistring:
  260. emitcall ('FPC_READ_TEXT_ANSISTRING',true);
  261. st_longstring:
  262. emitcall ('FPC_READ_TEXT_LONGSTRING',true);
  263. st_widestring:
  264. emitcall ('FPC_READ_TEXT_ANSISTRING',true);
  265. end
  266. end
  267. else
  268. Case pstringdef(Pararesult)^.string_typ of
  269. st_shortstring:
  270. emitcall ('FPC_WRITE_TEXT_STRING',true);
  271. st_ansistring:
  272. emitcall ('FPC_WRITE_TEXT_ANSISTRING',true);
  273. st_longstring:
  274. emitcall ('FPC_WRITE_TEXT_LONGSTRING',true);
  275. st_widestring:
  276. emitcall ('FPC_WRITE_TEXT_ANSISTRING',true);
  277. end;
  278. end;
  279. pointerdef : begin
  280. if is_equal(ppointerdef(pararesult)^.definition,cchardef) then
  281. begin
  282. if doread then
  283. emitcall('FPC_READ_TEXT_PCHAR_AS_POINTER',true)
  284. else
  285. emitcall('FPC_WRITE_TEXT_PCHAR_AS_POINTER',true);
  286. end;
  287. end;
  288. arraydef : begin
  289. if is_chararray(pararesult) then
  290. begin
  291. if doread then
  292. emitcall('FPC_READ_TEXT_PCHAR_AS_ARRAY',true)
  293. else
  294. emitcall('FPC_WRITE_TEXT_PCHAR_AS_ARRAY',true);
  295. end;
  296. end;
  297. floatdef : begin
  298. if doread then
  299. emitcall('FPC_READ_TEXT_'+float_name[pfloatdef(pararesult)^.typ],true)
  300. else
  301. emitcall('FPC_WRITE_TEXT_'+float_name[pfloatdef(pararesult)^.typ],true);
  302. end;
  303. orddef : begin
  304. case porddef(pararesult)^.typ of
  305. u8bit : if doread then
  306. emitcall('FPC_READ_TEXT_BYTE',true);
  307. s8bit : if doread then
  308. emitcall('FPC_READ_TEXT_SHORTINT',true);
  309. u16bit : if doread then
  310. emitcall('FPC_READ_TEXT_WORD',true);
  311. s16bit : if doread then
  312. emitcall('FPC_READ_TEXT_INTEGER',true);
  313. s32bit : if doread then
  314. emitcall('FPC_READ_TEXT_LONGINT',true)
  315. else
  316. emitcall('FPC_WRITE_TEXT_LONGINT',true);
  317. u32bit : if doread then
  318. emitcall('FPC_READ_TEXT_CARDINAL',true)
  319. else
  320. emitcall('FPC_WRITE_TEXT_CARDINAL',true);
  321. uchar : if doread then
  322. emitcall('FPC_READ_TEXT_CHAR',true)
  323. else
  324. emitcall('FPC_WRITE_TEXT_CHAR',true);
  325. s64bitint:
  326. if doread then
  327. emitcall('FPC_READ_TEXT_INT64',true)
  328. else
  329. emitcall('FPC_WRITE_TEXT_INT64',true);
  330. u64bit : if doread then
  331. emitcall('FPC_READ_TEXT_QWORD',true)
  332. else
  333. emitcall('FPC_WRITE_TEXT_QWORD',true);
  334. bool8bit,
  335. bool16bit,
  336. bool32bit : if doread then
  337. CGMessage(parser_e_illegal_parameter_list)
  338. else
  339. emitcall('FPC_WRITE_TEXT_BOOLEAN',true);
  340. end;
  341. end;
  342. end;
  343. end;
  344. { load ESI in methods again }
  345. popusedregisters(pushed);
  346. maybe_loadesi;
  347. end;
  348. end;
  349. { Insert end of writing for textfiles }
  350. if ft=ft_text then
  351. begin
  352. pushusedregisters(pushed,$ff);
  353. emit_push_mem(aktfile);
  354. if doread then
  355. begin
  356. if doln then
  357. emitcall('FPC_READLN_END',true)
  358. else
  359. emitcall('FPC_READ_END',true);
  360. end
  361. else
  362. begin
  363. if doln then
  364. emitcall('FPC_WRITELN_END',true)
  365. else
  366. emitcall('FPC_WRITE_END',true);
  367. end;
  368. popusedregisters(pushed);
  369. maybe_loadesi;
  370. end;
  371. { Insert IOCheck if set }
  372. if assigned(iolabel) then
  373. begin
  374. { registers are saved in the procedure }
  375. exprasmlist^.concat(new(pai386,op_csymbol(A_PUSH,S_L,newcsymbol(lab2str(iolabel),0))));
  376. emitcall('FPC_IOCHECK',true);
  377. end;
  378. { Freeup all used temps }
  379. ungetiftemp(aktfile);
  380. if assigned(p^.left) then
  381. begin
  382. p^.left:=reversparameter(p^.left);
  383. if npara<>nb_para then
  384. CGMessage(cg_f_internal_error_in_secondinline);
  385. hp:=p^.left;
  386. while assigned(hp) do
  387. begin
  388. if assigned(hp^.left) then
  389. if (hp^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  390. ungetiftemp(hp^.left^.location.reference);
  391. hp:=hp^.right;
  392. end;
  393. end;
  394. end;
  395. procedure handle_str;
  396. var
  397. hp,node : ptree;
  398. dummycoll : tdefcoll;
  399. is_real,has_length : boolean;
  400. procedureprefix : string;
  401. begin
  402. pushusedregisters(pushed,$ff);
  403. node:=p^.left;
  404. is_real:=false;
  405. has_length:=false;
  406. while assigned(node^.right) do node:=node^.right;
  407. { if a real parameter somewhere then call REALSTR }
  408. if (node^.left^.resulttype^.deftype=floatdef) then
  409. is_real:=true;
  410. node:=p^.left;
  411. { we have at least two args }
  412. { with at max 2 colon_para in between }
  413. { string arg }
  414. hp:=node;
  415. node:=node^.right;
  416. hp^.right:=nil;
  417. dummycoll.paratyp:=vs_var;
  418. if is_shortstring(hp^.resulttype) then
  419. dummycoll.data:=openshortstringdef
  420. else
  421. dummycoll.data:=hp^.resulttype;
  422. case pstringdef(hp^.resulttype)^.string_typ of
  423. st_widestring:
  424. procedureprefix:='FPC_STRWIDE_';
  425. st_ansistring:
  426. procedureprefix:='FPC_STRANSI_';
  427. st_shortstring:
  428. procedureprefix:='FPC_STR_';
  429. st_longstring:
  430. procedureprefix:='FPC_STRLONG_';
  431. end;
  432. secondcallparan(hp,@dummycoll,false,false,0);
  433. if codegenerror then
  434. exit;
  435. dummycoll.paratyp:=vs_const;
  436. disposetree(p^.left);
  437. p^.left:=nil;
  438. { second arg }
  439. hp:=node;
  440. node:=node^.right;
  441. hp^.right:=nil;
  442. { frac para }
  443. if hp^.is_colon_para and assigned(node) and
  444. node^.is_colon_para then
  445. begin
  446. dummycoll.data:=hp^.resulttype;
  447. secondcallparan(hp,@dummycoll,false
  448. ,false,0
  449. );
  450. if codegenerror then
  451. exit;
  452. disposetree(hp);
  453. hp:=node;
  454. node:=node^.right;
  455. hp^.right:=nil;
  456. has_length:=true;
  457. end
  458. else
  459. if is_real then
  460. push_int(-1);
  461. { third arg, length only if is_real }
  462. if hp^.is_colon_para then
  463. begin
  464. dummycoll.data:=hp^.resulttype;
  465. secondcallparan(hp,@dummycoll,false
  466. ,false,0
  467. );
  468. if codegenerror then
  469. exit;
  470. disposetree(hp);
  471. hp:=node;
  472. node:=node^.right;
  473. hp^.right:=nil;
  474. end
  475. else
  476. if is_real then
  477. push_int(-32767)
  478. else
  479. push_int(-1);
  480. { last arg longint or real }
  481. secondcallparan(hp,@dummycoll,false
  482. ,false,0
  483. );
  484. disposetree(hp);
  485. if codegenerror then
  486. exit;
  487. if is_real then
  488. emitcall(procedureprefix++float_name[pfloatdef(hp^.resulttype)^.typ],true)
  489. else
  490. case porddef(hp^.resulttype)^.typ of
  491. u32bit:
  492. emitcall(procedureprefix+'CARDINAL',true);
  493. u64bit:
  494. emitcall(procedureprefix+'QWORD',true);
  495. s64bitint:
  496. emitcall(procedureprefix+'INT64',true);
  497. else
  498. emitcall(procedureprefix+'LONGINT',true);
  499. end;
  500. popusedregisters(pushed);
  501. end;
  502. var
  503. r : preference;
  504. hp : ptree;
  505. l : longint;
  506. ispushed : boolean;
  507. hregister : tregister;
  508. otlabel,oflabel : plabel;
  509. oldpushedparasize : longint;
  510. oldrl : plinkedlist;
  511. begin
  512. { save & reset pushedparasize }
  513. oldpushedparasize:=pushedparasize;
  514. pushedparasize:=0;
  515. case p^.inlinenumber of
  516. in_assert_x_y:
  517. begin
  518. otlabel:=truelabel;
  519. oflabel:=falselabel;
  520. getlabel(truelabel);
  521. getlabel(falselabel);
  522. secondpass(p^.left^.left);
  523. if cs_do_assertion in aktlocalswitches then
  524. begin
  525. maketojumpbool(p^.left^.left);
  526. emitl(A_LABEL,falselabel);
  527. { erroraddr }
  528. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EBP)));
  529. { lineno }
  530. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,aktfilepos.line)));
  531. { filename string }
  532. hp:=genstringconstnode(current_module^.sourcefiles^.get_file_name(aktfilepos.fileindex));
  533. secondpass(hp);
  534. if codegenerror then
  535. exit;
  536. emitpushreferenceaddr(exprasmlist,hp^.location.reference);
  537. disposetree(hp);
  538. { push msg }
  539. secondpass(p^.left^.right^.left);
  540. emitpushreferenceaddr(exprasmlist,p^.left^.right^.left^.location.reference);
  541. { call }
  542. emitcall('FPC_ASSERT',true);
  543. emitl(A_LABEL,truelabel);
  544. end;
  545. freelabel(truelabel);
  546. freelabel(falselabel);
  547. truelabel:=otlabel;
  548. falselabel:=oflabel;
  549. end;
  550. in_lo_word,
  551. in_hi_word :
  552. begin
  553. secondpass(p^.left);
  554. p^.location.loc:=LOC_REGISTER;
  555. if p^.left^.location.loc<>LOC_REGISTER then
  556. begin
  557. if p^.left^.location.loc=LOC_CREGISTER then
  558. begin
  559. p^.location.register:=reg32toreg16(getregister32);
  560. emit_reg_reg(A_MOV,S_W,p^.left^.location.register,
  561. p^.location.register);
  562. end
  563. else
  564. begin
  565. del_reference(p^.left^.location.reference);
  566. p^.location.register:=reg32toreg16(getregister32);
  567. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_W,newreference(p^.left^.location.reference),
  568. p^.location.register)));
  569. end;
  570. end
  571. else p^.location.register:=p^.left^.location.register;
  572. if p^.inlinenumber=in_hi_word then
  573. exprasmlist^.concat(new(pai386,op_const_reg(A_SHR,S_W,8,p^.location.register)));
  574. p^.location.register:=reg16toreg8(p^.location.register);
  575. end;
  576. {$ifdef OLDHIGH}
  577. in_high_x :
  578. begin
  579. if is_open_array(p^.left^.resulttype) or
  580. is_open_string(p^.left^.resulttype) then
  581. begin
  582. secondpass(p^.left);
  583. del_reference(p^.left^.location.reference);
  584. p^.location.register:=getregister32;
  585. r:=new_reference(highframepointer,highoffset+4);
  586. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  587. r,p^.location.register)));
  588. end
  589. end;
  590. {$endif OLDHIGH}
  591. in_sizeof_x,
  592. in_typeof_x :
  593. begin
  594. {$ifdef OLDHIGH}
  595. { sizeof(openarray) handling }
  596. if (p^.inlinenumber=in_sizeof_x) and
  597. (is_open_array(p^.left^.resulttype) or
  598. is_open_string(p^.left^.resulttype)) then
  599. begin
  600. { sizeof(openarray)=high(openarray)+1 }
  601. secondpass(p^.left);
  602. del_reference(p^.left^.location.reference);
  603. p^.location.register:=getregister32;
  604. r:=new_reference(highframepointer,highoffset+4);
  605. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  606. r,p^.location.register)));
  607. exprasmlist^.concat(new(pai386,op_reg(A_INC,S_L,
  608. p^.location.register)));
  609. if (p^.left^.resulttype^.deftype=arraydef) and
  610. (parraydef(p^.left^.resulttype)^.elesize<>1) then
  611. exprasmlist^.concat(new(pai386,op_const_reg(A_IMUL,S_L,
  612. parraydef(p^.left^.resulttype)^.elesize,p^.location.register)));
  613. end
  614. else
  615. {$endif OLDHIGH}
  616. begin
  617. { for both cases load vmt }
  618. if p^.left^.treetype=typen then
  619. begin
  620. p^.location.register:=getregister32;
  621. exprasmlist^.concat(new(pai386,op_csymbol_reg(A_MOV,
  622. S_L,newcsymbol(pobjectdef(p^.left^.resulttype)^.vmt_mangledname,0),
  623. p^.location.register)));
  624. end
  625. else
  626. begin
  627. secondpass(p^.left);
  628. del_reference(p^.left^.location.reference);
  629. p^.location.loc:=LOC_REGISTER;
  630. p^.location.register:=getregister32;
  631. { load VMT pointer }
  632. inc(p^.left^.location.reference.offset,
  633. pobjectdef(p^.left^.resulttype)^.vmt_offset);
  634. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  635. newreference(p^.left^.location.reference),
  636. p^.location.register)));
  637. end;
  638. { in sizeof load size }
  639. if p^.inlinenumber=in_sizeof_x then
  640. begin
  641. new(r);
  642. reset_reference(r^);
  643. r^.base:=p^.location.register;
  644. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,
  645. p^.location.register)));
  646. end;
  647. end;
  648. end;
  649. in_lo_long,
  650. in_hi_long :
  651. begin
  652. secondpass(p^.left);
  653. p^.location.loc:=LOC_REGISTER;
  654. if p^.left^.location.loc<>LOC_REGISTER then
  655. begin
  656. if p^.left^.location.loc=LOC_CREGISTER then
  657. begin
  658. p^.location.register:=getregister32;
  659. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  660. p^.location.register);
  661. end
  662. else
  663. begin
  664. del_reference(p^.left^.location.reference);
  665. p^.location.register:=getregister32;
  666. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  667. p^.location.register)));
  668. end;
  669. end
  670. else p^.location.register:=p^.left^.location.register;
  671. if p^.inlinenumber=in_hi_long then
  672. exprasmlist^.concat(new(pai386,op_const_reg(A_SHR,S_L,16,p^.location.register)));
  673. p^.location.register:=reg32toreg16(p^.location.register);
  674. end;
  675. in_length_string :
  676. begin
  677. secondpass(p^.left);
  678. set_location(p^.location,p^.left^.location);
  679. { length in ansi strings is at offset -8 }
  680. if is_ansistring(p^.left^.resulttype) then
  681. dec(p^.location.reference.offset,8)
  682. { char is always 1, so make it a constant value }
  683. else if is_char(p^.left^.resulttype) then
  684. begin
  685. clear_location(p^.location);
  686. p^.location.loc:=LOC_MEM;
  687. p^.location.reference.isintvalue:=true;
  688. p^.location.reference.offset:=1;
  689. end;
  690. end;
  691. in_pred_x,
  692. in_succ_x:
  693. begin
  694. secondpass(p^.left);
  695. if p^.inlinenumber=in_pred_x then
  696. asmop:=A_DEC
  697. else
  698. asmop:=A_INC;
  699. case p^.resulttype^.size of
  700. 4 : opsize:=S_L;
  701. 2 : opsize:=S_W;
  702. 1 : opsize:=S_B;
  703. else
  704. internalerror(10080);
  705. end;
  706. p^.location.loc:=LOC_REGISTER;
  707. if p^.left^.location.loc<>LOC_REGISTER then
  708. begin
  709. p^.location.register:=getregister32;
  710. if (p^.resulttype^.size=2) then
  711. p^.location.register:=reg32toreg16(p^.location.register);
  712. if (p^.resulttype^.size=1) then
  713. p^.location.register:=reg32toreg8(p^.location.register);
  714. if p^.left^.location.loc=LOC_CREGISTER then
  715. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  716. p^.location.register)
  717. else
  718. if p^.left^.location.loc=LOC_FLAGS then
  719. exprasmlist^.concat(new(pai386,op_reg(flag_2_set[p^.left^.location.resflags],S_B,
  720. p^.location.register)))
  721. else
  722. begin
  723. del_reference(p^.left^.location.reference);
  724. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,newreference(p^.left^.location.reference),
  725. p^.location.register)));
  726. end;
  727. end
  728. else p^.location.register:=p^.left^.location.register;
  729. exprasmlist^.concat(new(pai386,op_reg(asmop,opsize,
  730. p^.location.register)));
  731. emitoverflowcheck(p);
  732. emitrangecheck(p,p^.resulttype);
  733. end;
  734. in_dec_x,
  735. in_inc_x :
  736. begin
  737. { set defaults }
  738. addvalue:=1;
  739. addconstant:=true;
  740. { load first parameter, must be a reference }
  741. secondpass(p^.left^.left);
  742. case p^.left^.left^.resulttype^.deftype of
  743. orddef,
  744. enumdef : begin
  745. case p^.left^.left^.resulttype^.size of
  746. 1 : opsize:=S_B;
  747. 2 : opsize:=S_W;
  748. 4 : opsize:=S_L;
  749. end;
  750. end;
  751. pointerdef : begin
  752. opsize:=S_L;
  753. if porddef(ppointerdef(p^.left^.left^.resulttype)^.definition)=voiddef then
  754. addvalue:=1
  755. else
  756. addvalue:=ppointerdef(p^.left^.left^.resulttype)^.definition^.savesize;
  757. end;
  758. else
  759. internalerror(10081);
  760. end;
  761. { second argument specified?, must be a s32bit in register }
  762. if assigned(p^.left^.right) then
  763. begin
  764. secondpass(p^.left^.right^.left);
  765. { when constant, just multiply the addvalue }
  766. if is_constintnode(p^.left^.right^.left) then
  767. addvalue:=addvalue*get_ordinal_value(p^.left^.right^.left)
  768. else
  769. begin
  770. case p^.left^.right^.left^.location.loc of
  771. LOC_REGISTER,
  772. LOC_CREGISTER : hregister:=p^.left^.right^.left^.location.register;
  773. LOC_MEM,
  774. LOC_REFERENCE : begin
  775. del_reference(p^.left^.right^.left^.location.reference);
  776. hregister:=getregister32;
  777. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  778. newreference(p^.left^.right^.left^.location.reference),hregister)));
  779. end;
  780. else
  781. internalerror(10082);
  782. end;
  783. { insert multiply with addvalue if its >1 }
  784. if addvalue>1 then
  785. exprasmlist^.concat(new(pai386,op_const_reg(A_IMUL,opsize,
  786. addvalue,hregister)));
  787. addconstant:=false;
  788. end;
  789. end;
  790. { write the add instruction }
  791. if addconstant then
  792. begin
  793. if (addvalue=1) and not(cs_check_overflow in aktlocalswitches) then
  794. begin
  795. if p^.left^.left^.location.loc=LOC_CREGISTER then
  796. exprasmlist^.concat(new(pai386,op_reg(incdecop[p^.inlinenumber],opsize,
  797. p^.left^.left^.location.register)))
  798. else
  799. exprasmlist^.concat(new(pai386,op_ref(incdecop[p^.inlinenumber],opsize,
  800. newreference(p^.left^.left^.location.reference))))
  801. end
  802. else
  803. begin
  804. if p^.left^.left^.location.loc=LOC_CREGISTER then
  805. exprasmlist^.concat(new(pai386,op_const_reg(addsubop[p^.inlinenumber],opsize,
  806. addvalue,p^.left^.left^.location.register)))
  807. else
  808. exprasmlist^.concat(new(pai386,op_const_ref(addsubop[p^.inlinenumber],opsize,
  809. addvalue,newreference(p^.left^.left^.location.reference))));
  810. end
  811. end
  812. else
  813. begin
  814. { BUG HERE : detected with nasm :
  815. hregister is allways 32 bit
  816. it should be converted to 16 or 8 bit depending on op_size PM }
  817. { still not perfect :
  818. if hregister is already a 16 bit reg ?? PM }
  819. case opsize of
  820. S_B : hregister:=reg32toreg8(hregister);
  821. S_W : hregister:=reg32toreg16(hregister);
  822. end;
  823. if p^.left^.left^.location.loc=LOC_CREGISTER then
  824. exprasmlist^.concat(new(pai386,op_reg_reg(addsubop[p^.inlinenumber],opsize,
  825. hregister,p^.left^.left^.location.register)))
  826. else
  827. exprasmlist^.concat(new(pai386,op_reg_ref(addsubop[p^.inlinenumber],opsize,
  828. hregister,newreference(p^.left^.left^.location.reference))));
  829. case opsize of
  830. S_B : hregister:=reg8toreg32(hregister);
  831. S_W : hregister:=reg16toreg32(hregister);
  832. end;
  833. ungetregister32(hregister);
  834. end;
  835. emitoverflowcheck(p^.left^.left);
  836. emitrangecheck(p^.left^.left,p^.left^.left^.resulttype);
  837. end;
  838. in_assigned_x :
  839. begin
  840. secondpass(p^.left^.left);
  841. p^.location.loc:=LOC_FLAGS;
  842. if (p^.left^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  843. begin
  844. exprasmlist^.concat(new(pai386,op_reg_reg(A_OR,S_L,
  845. p^.left^.left^.location.register,
  846. p^.left^.left^.location.register)));
  847. ungetregister32(p^.left^.left^.location.register);
  848. end
  849. else
  850. begin
  851. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_L,0,
  852. newreference(p^.left^.left^.location.reference))));
  853. del_reference(p^.left^.left^.location.reference);
  854. end;
  855. p^.location.resflags:=F_NE;
  856. end;
  857. in_reset_typedfile,in_rewrite_typedfile :
  858. begin
  859. pushusedregisters(pushed,$ff);
  860. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,pfiledef(p^.left^.resulttype)^.typed_as^.size)));
  861. secondload(p^.left);
  862. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  863. if p^.inlinenumber=in_reset_typedfile then
  864. emitcall('FPC_RESET_TYPED',true)
  865. else
  866. emitcall('FPC_REWRITE_TYPED',true);
  867. popusedregisters(pushed);
  868. end;
  869. in_write_x :
  870. handlereadwrite(false,false);
  871. in_writeln_x :
  872. handlereadwrite(false,true);
  873. in_read_x :
  874. handlereadwrite(true,false);
  875. in_readln_x :
  876. handlereadwrite(true,true);
  877. in_str_x_string :
  878. begin
  879. handle_str;
  880. maybe_loadesi;
  881. end;
  882. in_include_x_y,
  883. in_exclude_x_y:
  884. begin
  885. secondpass(p^.left^.left);
  886. if p^.left^.right^.left^.treetype=ordconstn then
  887. begin
  888. { calculate bit position }
  889. l:=1 shl (p^.left^.right^.left^.value mod 32);
  890. { determine operator }
  891. if p^.inlinenumber=in_include_x_y then
  892. asmop:=A_OR
  893. else
  894. begin
  895. asmop:=A_AND;
  896. l:=not(l);
  897. end;
  898. if (p^.left^.left^.location.loc=LOC_REFERENCE) then
  899. begin
  900. inc(p^.left^.left^.location.reference.offset,(p^.left^.right^.left^.value div 32)*4);
  901. exprasmlist^.concat(new(pai386,op_const_ref(asmop,S_L,
  902. l,newreference(p^.left^.left^.location.reference))));
  903. del_reference(p^.left^.left^.location.reference);
  904. end
  905. else
  906. { LOC_CREGISTER }
  907. exprasmlist^.concat(new(pai386,op_const_reg(asmop,S_L,
  908. l,p^.left^.left^.location.register)));
  909. end
  910. else
  911. begin
  912. { generate code for the element to set }
  913. ispushed:=maybe_push(p^.left^.right^.left^.registers32,p^.left^.left);
  914. secondpass(p^.left^.right^.left);
  915. if ispushed then
  916. restore(p^.left^.left);
  917. { determine asm operator }
  918. if p^.inlinenumber=in_include_x_y then
  919. asmop:=A_BTS
  920. else
  921. asmop:=A_BTR;
  922. if psetdef(p^.left^.resulttype)^.settype=smallset then
  923. begin
  924. if p^.left^.right^.left^.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  925. hregister:=p^.left^.right^.left^.location.register
  926. else
  927. begin
  928. hregister:=R_EDI;
  929. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  930. newreference(p^.left^.right^.left^.location.reference),R_EDI)));
  931. end;
  932. if (p^.left^.left^.location.loc=LOC_REFERENCE) then
  933. exprasmlist^.concat(new(pai386,op_reg_ref(asmop,S_L,hregister,
  934. newreference(p^.left^.right^.left^.location.reference))))
  935. else
  936. exprasmlist^.concat(new(pai386,op_reg_reg(asmop,S_L,hregister,
  937. p^.left^.right^.left^.location.register)));
  938. end
  939. else
  940. begin
  941. pushsetelement(p^.left^.right^.left);
  942. { normset is allways a ref }
  943. emitpushreferenceaddr(exprasmlist,
  944. p^.left^.left^.location.reference);
  945. if p^.inlinenumber=in_include_x_y then
  946. emitcall('FPC_SET_SET_BYTE',true)
  947. else
  948. emitcall('FPC_SET_UNSET_BYTE',true);
  949. {CGMessage(cg_e_include_not_implemented);}
  950. end;
  951. end;
  952. end;
  953. else internalerror(9);
  954. end;
  955. { remove temp. objects, we don't generate them here }
  956. removetemps(exprasmlist,temptoremove);
  957. temptoremove^.clear;
  958. { reset pushedparasize }
  959. pushedparasize:=oldpushedparasize;
  960. end;
  961. end.
  962. {
  963. $Log$
  964. Revision 1.25 1999-02-05 10:56:19 florian
  965. * in some cases a writeln of temp. ansistrings cause a memory leak, fixed
  966. Revision 1.24 1999/01/21 22:10:39 peter
  967. * fixed array of const
  968. * generic platform independent high() support
  969. Revision 1.23 1999/01/06 12:23:29 florian
  970. * str(...) for ansi/long and widestrings fixed
  971. Revision 1.22 1998/12/11 23:36:07 florian
  972. + again more stuff for int64/qword:
  973. - comparision operators
  974. - code generation for: str, read(ln), write(ln)
  975. Revision 1.21 1998/12/11 00:02:50 peter
  976. + globtype,tokens,version unit splitted from globals
  977. Revision 1.20 1998/11/27 14:50:32 peter
  978. + open strings, $P switch support
  979. Revision 1.19 1998/11/26 13:10:40 peter
  980. * new int - int conversion -dNEWCNV
  981. * some function renamings
  982. Revision 1.18 1998/11/24 17:04:27 peter
  983. * fixed length(char) when char is a variable
  984. Revision 1.17 1998/11/05 12:02:33 peter
  985. * released useansistring
  986. * removed -Sv, its now available in fpc modes
  987. Revision 1.16 1998/10/22 17:11:13 pierre
  988. + terminated the include exclude implementation for i386
  989. * enums inside records fixed
  990. Revision 1.15 1998/10/21 15:12:50 pierre
  991. * bug fix for IOCHECK inside a procedure with iocheck modifier
  992. * removed the GPF for unexistant overloading
  993. (firstcall was called with procedinition=nil !)
  994. * changed typen to what Florian proposed
  995. gentypenode(p : pdef) sets the typenodetype field
  996. and resulttype is only set if inside bt_type block !
  997. Revision 1.14 1998/10/20 08:06:40 pierre
  998. * several memory corruptions due to double freemem solved
  999. => never use p^.loc.location:=p^.left^.loc.location;
  1000. + finally I added now by default
  1001. that ra386dir translates global and unit symbols
  1002. + added a first field in tsymtable and
  1003. a nextsym field in tsym
  1004. (this allows to obtain ordered type info for
  1005. records and objects in gdb !)
  1006. Revision 1.13 1998/10/13 16:50:02 pierre
  1007. * undid some changes of Peter that made the compiler wrong
  1008. for m68k (I had to reinsert some ifdefs)
  1009. * removed several memory leaks under m68k
  1010. * removed the meory leaks for assembler readers
  1011. * cross compiling shoud work again better
  1012. ( crosscompiling sysamiga works
  1013. but as68k still complain about some code !)
  1014. Revision 1.12 1998/10/08 17:17:12 pierre
  1015. * current_module old scanner tagged as invalid if unit is recompiled
  1016. + added ppheap for better info on tracegetmem of heaptrc
  1017. (adds line column and file index)
  1018. * several memory leaks removed ith help of heaptrc !!
  1019. Revision 1.11 1998/10/05 21:33:15 peter
  1020. * fixed 161,165,166,167,168
  1021. Revision 1.10 1998/10/05 12:32:44 peter
  1022. + assert() support
  1023. Revision 1.8 1998/10/02 10:35:09 peter
  1024. * support for inc(pointer,value) which now increases with value instead
  1025. of 0*value :)
  1026. Revision 1.7 1998/09/21 08:45:07 pierre
  1027. + added vmt_offset in tobjectdef.write for fututre use
  1028. (first steps to have objects without vmt if no virtual !!)
  1029. + added fpu_used field for tabstractprocdef :
  1030. sets this level to 2 if the functions return with value in FPU
  1031. (is then set to correct value at parsing of implementation)
  1032. THIS MIGHT refuse some code with FPU expression too complex
  1033. that were accepted before and even in some cases
  1034. that don't overflow in fact
  1035. ( like if f : float; is a forward that finally in implementation
  1036. only uses one fpu register !!)
  1037. Nevertheless I think that it will improve security on
  1038. FPU operations !!
  1039. * most other changes only for UseBrowser code
  1040. (added symtable references for record and objects)
  1041. local switch for refs to args and local of each function
  1042. (static symtable still missing)
  1043. UseBrowser still not stable and probably broken by
  1044. the definition hash array !!
  1045. Revision 1.6 1998/09/20 12:26:37 peter
  1046. * merged fixes
  1047. Revision 1.5 1998/09/17 09:42:15 peter
  1048. + pass_2 for cg386
  1049. * Message() -> CGMessage() for pass_1/pass_2
  1050. Revision 1.4 1998/09/14 10:43:49 peter
  1051. * all internal RTL functions start with FPC_
  1052. Revision 1.3.2.1 1998/09/20 12:20:07 peter
  1053. * Fixed stack not on 4 byte boundary when doing a call
  1054. Revision 1.3 1998/09/05 23:03:57 florian
  1055. * some fixes to get -Or work:
  1056. - inc/dec didn't take care of CREGISTER
  1057. - register calculcation of inc/dec was wrong
  1058. - var/const parameters get now assigned 32 bit register, but
  1059. const parameters only if they are passed by reference !
  1060. Revision 1.2 1998/09/04 08:41:40 peter
  1061. * updated some error CGMessages
  1062. Revision 1.1 1998/08/31 12:22:14 peter
  1063. * secondinline moved to cg386inl
  1064. Revision 1.19 1998/08/31 08:52:03 peter
  1065. * fixed error 10 with succ() and pref()
  1066. Revision 1.18 1998/08/20 21:36:38 peter
  1067. * fixed 'with object do' bug
  1068. Revision 1.17 1998/08/19 16:07:36 jonas
  1069. * changed optimizer switches + cleanup of DestroyRefs in daopt386.pas
  1070. Revision 1.16 1998/08/18 09:24:36 pierre
  1071. * small warning position bug fixed
  1072. * support_mmx switches splitting was missing
  1073. * rhide error and warning output corrected
  1074. Revision 1.15 1998/08/13 11:00:09 peter
  1075. * fixed procedure<>procedure construct
  1076. Revision 1.14 1998/08/11 14:05:33 peter
  1077. * fixed sizeof(array of char)
  1078. Revision 1.13 1998/08/10 14:49:45 peter
  1079. + localswitches, moduleswitches, globalswitches splitting
  1080. Revision 1.12 1998/07/30 13:30:31 florian
  1081. * final implemenation of exception support, maybe it needs
  1082. some fixes :)
  1083. Revision 1.11 1998/07/24 22:16:52 florian
  1084. * internal error 10 together with array access fixed. I hope
  1085. that's the final fix.
  1086. Revision 1.10 1998/07/18 22:54:23 florian
  1087. * some ansi/wide/longstring support fixed:
  1088. o parameter passing
  1089. o returning as result from functions
  1090. Revision 1.9 1998/07/07 17:40:37 peter
  1091. * packrecords 4 works
  1092. * word aligning of parameters
  1093. Revision 1.8 1998/07/06 15:51:15 michael
  1094. Added length checking for string reading
  1095. Revision 1.7 1998/07/06 14:19:51 michael
  1096. + Added calls for reading/writing ansistrings
  1097. Revision 1.6 1998/07/01 15:28:48 peter
  1098. + better writeln/readln handling, now 100% like tp7
  1099. Revision 1.5 1998/06/25 14:04:17 peter
  1100. + internal inc/dec
  1101. Revision 1.4 1998/06/25 08:48:06 florian
  1102. * first version of rtti support
  1103. Revision 1.3 1998/06/09 16:01:33 pierre
  1104. + added procedure directive parsing for procvars
  1105. (accepted are popstack cdecl and pascal)
  1106. + added C vars with the following syntax
  1107. var C calias 'true_c_name';(can be followed by external)
  1108. reason is that you must add the Cprefix
  1109. which is target dependent
  1110. Revision 1.2 1998/06/08 13:13:29 pierre
  1111. + temporary variables now in temp_gen.pas unit
  1112. because it is processor independent
  1113. * mppc68k.bat modified to undefine i386 and support_mmx
  1114. (which are defaults for i386)
  1115. Revision 1.1 1998/06/05 17:44:10 peter
  1116. * splitted cgi386
  1117. }