cg386inl.pas 51 KB

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