cg386inl.pas 47 KB

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