ncginl.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Carl Eric Codere
  4. Generate generic 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 ncginl;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,ninl;
  23. type
  24. tcginlinenode = class(tinlinenode)
  25. procedure pass_2;override;
  26. { Handle the assert routine }
  27. procedure second_assert;virtual;
  28. procedure second_sizeoftypeof;virtual;
  29. procedure second_length;virtual;
  30. procedure second_predsucc;virtual;
  31. procedure second_incdec;virtual;
  32. procedure second_typeinfo;virtual;
  33. procedure second_assigned;virtual;
  34. procedure second_includeexclude;virtual;
  35. procedure second_pi; virtual;
  36. procedure second_arctan_real; virtual;
  37. procedure second_abs_real; virtual;
  38. procedure second_sqr_real; virtual;
  39. procedure second_sqrt_real; virtual;
  40. procedure second_ln_real; virtual;
  41. procedure second_cos_real; virtual;
  42. procedure second_sin_real; virtual;
  43. end;
  44. implementation
  45. uses
  46. globtype,systems,
  47. cutils,verbose,globals,fmodule,
  48. symconst,symdef,defbase,
  49. aasmbase,aasmtai,aasmcpu,
  50. cginfo,cgbase,pass_1,pass_2,
  51. cpubase,paramgr,
  52. nbas,ncon,ncal,ncnv,nld,
  53. cga,tgobj,ncgutil,cgobj,cg64f32,rgobj,rgcpu;
  54. {*****************************************************************************
  55. TCGINLINENODE
  56. *****************************************************************************}
  57. procedure tcginlinenode.pass_2;
  58. var
  59. asmop : tasmop;
  60. l : longint;
  61. oldpushedparasize : longint;
  62. begin
  63. { save & reset pushedparasize }
  64. oldpushedparasize:=pushedparasize;
  65. pushedparasize:=0;
  66. case inlinenumber of
  67. in_assert_x_y:
  68. begin
  69. second_Assert;
  70. end;
  71. in_sizeof_x,
  72. in_typeof_x :
  73. begin
  74. second_SizeofTypeOf;
  75. end;
  76. in_length_x :
  77. begin
  78. second_Length;
  79. end;
  80. in_pred_x,
  81. in_succ_x:
  82. begin
  83. second_PredSucc;
  84. end;
  85. in_dec_x,
  86. in_inc_x :
  87. begin
  88. second_IncDec;
  89. end;
  90. in_typeinfo_x:
  91. begin
  92. second_TypeInfo;
  93. end;
  94. in_assigned_x :
  95. begin
  96. second_Assigned;
  97. end;
  98. in_include_x_y,
  99. in_exclude_x_y:
  100. begin
  101. second_IncludeExclude;
  102. end;
  103. in_pi:
  104. begin
  105. second_pi;
  106. end;
  107. in_sin_extended:
  108. begin
  109. second_sin_real;
  110. end;
  111. in_arctan_extended:
  112. begin
  113. second_arctan_real;
  114. end;
  115. in_abs_extended:
  116. begin
  117. second_abs_real;
  118. end;
  119. in_sqr_extended:
  120. begin
  121. second_sqr_real;
  122. end;
  123. in_sqrt_extended:
  124. begin
  125. second_sqrt_real;
  126. end;
  127. in_ln_extended:
  128. begin
  129. second_ln_real;
  130. end;
  131. in_cos_extended:
  132. begin
  133. second_cos_real;
  134. end;
  135. {$ifdef SUPPORT_MMX}
  136. in_mmx_pcmpeqb..in_mmx_pcmpgtw:
  137. begin
  138. location_reset(location,LOC_MMXREGISTER,OS_NO);
  139. if left.location.loc=LOC_REGISTER then
  140. begin
  141. {!!!!!!!}
  142. end
  143. else if tcallparanode(left).left.location.loc=LOC_REGISTER then
  144. begin
  145. {!!!!!!!}
  146. end
  147. else
  148. begin
  149. {!!!!!!!}
  150. end;
  151. end;
  152. {$endif SUPPORT_MMX}
  153. else internalerror(9);
  154. end;
  155. { reset pushedparasize }
  156. pushedparasize:=oldpushedparasize;
  157. end;
  158. {*****************************************************************************
  159. ASSERT GENERIC HANDLING
  160. *****************************************************************************}
  161. procedure tcginlinenode.second_Assert;
  162. var
  163. hp2 : tstringconstnode;
  164. otlabel,oflabel{,l1} : tasmlabel;
  165. begin
  166. { the node should be removed in the firstpass }
  167. if not (cs_do_assertion in aktlocalswitches) then
  168. internalerror(7123458);
  169. otlabel:=truelabel;
  170. oflabel:=falselabel;
  171. getlabel(truelabel);
  172. getlabel(falselabel);
  173. secondpass(tcallparanode(left).left);
  174. maketojumpbool(exprasmlist,tcallparanode(left).left,lr_load_regvars);
  175. cg.a_label(exprasmlist,falselabel);
  176. { erroraddr }
  177. cg.a_param_reg(exprasmlist,OS_ADDR,FRAME_POINTER_REG,paramanager.getintparaloc(4));
  178. { lineno }
  179. cg.a_param_const(exprasmlist,OS_INT,aktfilepos.line,paramanager.getintparaloc(3));
  180. { filename string }
  181. hp2:=cstringconstnode.createstr(current_module.sourcefiles.get_file_name(aktfilepos.fileindex),st_shortstring);
  182. firstpass(hp2);
  183. secondpass(hp2);
  184. if codegenerror then
  185. exit;
  186. cg.a_paramaddr_ref(exprasmlist,hp2.location.reference,paramanager.getintparaloc(2));
  187. hp2.free;
  188. { push msg }
  189. secondpass(tcallparanode(tcallparanode(left).right).left);
  190. cg.a_paramaddr_ref(exprasmlist,tcallparanode(tcallparanode(left).right).left.location.reference,paramanager.getintparaloc(1));
  191. { call }
  192. cg.a_call_name(exprasmlist,'FPC_ASSERT');
  193. cg.a_label(exprasmlist,truelabel);
  194. truelabel:=otlabel;
  195. falselabel:=oflabel;
  196. end;
  197. {*****************************************************************************
  198. SIZEOF / TYPEOF GENERIC HANDLING
  199. *****************************************************************************}
  200. { second_handle_ the sizeof and typeof routines }
  201. procedure tcginlinenode.second_SizeOfTypeOf;
  202. var
  203. href : treference;
  204. hregister : tregister;
  205. begin
  206. location_reset(location,LOC_REGISTER,OS_ADDR);
  207. { for both cases load vmt }
  208. if left.nodetype=typen then
  209. begin
  210. hregister:=rg.getaddressregister(exprasmlist);
  211. reference_reset_symbol(href,newasmsymbol(tobjectdef(left.resulttype.def).vmt_mangledname),0);
  212. cg.a_loadaddr_ref_reg(exprasmlist,href,hregister);
  213. end
  214. else
  215. begin
  216. secondpass(left);
  217. location_release(exprasmlist,left.location);
  218. hregister:=rg.getaddressregister(exprasmlist);
  219. { load VMT pointer }
  220. inc(left.location.reference.offset,tobjectdef(left.resulttype.def).vmt_offset);
  221. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,hregister);
  222. end;
  223. { in sizeof load size }
  224. if inlinenumber=in_sizeof_x then
  225. begin
  226. reference_reset_base(href,hregister,0);
  227. rg.ungetaddressregister(exprasmlist,hregister);
  228. hregister:=rg.getregisterint(exprasmlist);
  229. cg.a_load_ref_reg(exprasmlist,OS_INT,href,hregister);
  230. end;
  231. location.register:=hregister;
  232. end;
  233. {*****************************************************************************
  234. LENGTH GENERIC HANDLING
  235. *****************************************************************************}
  236. procedure tcginlinenode.second_Length;
  237. var
  238. lengthlab : tasmlabel;
  239. hregister : tregister;
  240. href : treference;
  241. begin
  242. secondpass(left);
  243. { length in ansi strings is at offset -8 }
  244. if is_ansistring(left.resulttype.def) or
  245. is_widestring(left.resulttype.def) then
  246. begin
  247. location_force_reg(exprasmlist,left.location,OS_ADDR,false);
  248. hregister:=left.location.register;
  249. getlabel(lengthlab);
  250. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,hregister,lengthlab);
  251. reference_reset_base(href,hregister,-8);
  252. cg.a_load_ref_reg(exprasmlist,OS_INT,href,hregister);
  253. cg.a_label(exprasmlist,lengthlab);
  254. location_reset(location,LOC_REGISTER,OS_INT);
  255. location.register:=hregister;
  256. end
  257. else
  258. begin
  259. location_copy(location,left.location);
  260. location.size:=OS_8;
  261. end;
  262. end;
  263. {*****************************************************************************
  264. PRED/SUCC GENERIC HANDLING
  265. *****************************************************************************}
  266. procedure tcginlinenode.second_PredSucc;
  267. var
  268. cgsize : TCGSize;
  269. cgop : topcg;
  270. begin
  271. secondpass(left);
  272. if inlinenumber=in_pred_x then
  273. cgop:=OP_SUB
  274. else
  275. cgop:=OP_ADD;
  276. cgsize:=def_cgsize(resulttype.def);
  277. { we need a value in a register }
  278. location_copy(location,left.location);
  279. location_force_reg(exprasmlist,location,cgsize,false);
  280. if cgsize in [OS_64,OS_S64] then
  281. cg64.a_op64_const_reg(exprasmlist,cgop,1,
  282. location.register64)
  283. else
  284. cg.a_op_const_reg(exprasmlist,cgop,1,location.register);
  285. cg.g_overflowcheck(exprasmlist,self);
  286. cg.g_rangecheck(exprasmlist,self,resulttype.def);
  287. end;
  288. {*****************************************************************************
  289. INC/DEC GENERIC HANDLING
  290. *****************************************************************************}
  291. procedure tcginlinenode.second_IncDec;
  292. const
  293. addsubop:array[in_inc_x..in_dec_x] of TOpCG=(OP_ADD,OP_SUB);
  294. var
  295. addvalue : longint;
  296. addconstant : boolean;
  297. hregisterhi,
  298. hregister : tregister;
  299. cgsize : tcgsize;
  300. pushedregs : tmaybesave;
  301. begin
  302. { set defaults }
  303. addconstant:=true;
  304. { load first parameter, must be a reference }
  305. secondpass(tcallparanode(left).left);
  306. cgsize:=def_cgsize(tcallparanode(left).left.resulttype.def);
  307. { get addvalue }
  308. case tcallparanode(left).left.resulttype.def.deftype of
  309. orddef,
  310. enumdef :
  311. addvalue:=1;
  312. pointerdef :
  313. begin
  314. if is_void(tpointerdef(tcallparanode(left).left.resulttype.def).pointertype.def) then
  315. addvalue:=1
  316. else
  317. addvalue:=tpointerdef(tcallparanode(left).left.resulttype.def).pointertype.def.size;
  318. end;
  319. else
  320. internalerror(10081);
  321. end;
  322. { second_ argument specified?, must be a s32bit in register }
  323. if assigned(tcallparanode(left).right) then
  324. begin
  325. maybe_save(exprasmlist,tcallparanode(tcallparanode(left).right).left.registers32,
  326. tcallparanode(left).left.location,pushedregs);
  327. secondpass(tcallparanode(tcallparanode(left).right).left);
  328. maybe_restore(exprasmlist,tcallparanode(left).left.location,pushedregs);
  329. { when constant, just multiply the addvalue }
  330. if is_constintnode(tcallparanode(tcallparanode(left).right).left) then
  331. addvalue:=addvalue*get_ordinal_value(tcallparanode(tcallparanode(left).right).left)
  332. else
  333. begin
  334. location_force_reg(exprasmlist,tcallparanode(tcallparanode(left).right).left.location,cgsize,false);
  335. hregister:=tcallparanode(tcallparanode(left).right).left.location.register;
  336. hregisterhi:=tcallparanode(tcallparanode(left).right).left.location.registerhigh;
  337. { insert multiply with addvalue if its >1 }
  338. if addvalue>1 then
  339. cg.a_op_const_reg(exprasmlist,OP_IMUL,addvalue,hregister);
  340. addconstant:=false;
  341. end;
  342. end;
  343. { write the add instruction }
  344. if addconstant then
  345. begin
  346. if cgsize in [OS_64,OS_S64] then
  347. cg64.a_op64_const_loc(exprasmlist,addsubop[inlinenumber],
  348. addvalue,tcallparanode(left).left.location)
  349. else
  350. cg.a_op_const_loc(exprasmlist,addsubop[inlinenumber],
  351. addvalue,tcallparanode(left).left.location);
  352. end
  353. else
  354. begin
  355. if cgsize in [OS_64,OS_S64] then
  356. cg64.a_op64_reg_loc(exprasmlist,addsubop[inlinenumber],
  357. joinreg64(hregister,hregisterhi),tcallparanode(left).left.location)
  358. else
  359. cg.a_op_reg_loc(exprasmlist,addsubop[inlinenumber],
  360. hregister,tcallparanode(left).left.location);
  361. location_release(exprasmlist,tcallparanode(tcallparanode(left).right).left.location);
  362. end;
  363. cg.g_overflowcheck(exprasmlist,tcallparanode(left).left);
  364. cg.g_rangecheck(exprasmlist,tcallparanode(left).left,tcallparanode(left).left.resulttype.def);
  365. end;
  366. {*****************************************************************************
  367. TYPEINFO GENERIC HANDLING
  368. *****************************************************************************}
  369. procedure tcginlinenode.second_typeinfo;
  370. var
  371. href : treference;
  372. begin
  373. location_reset(location,LOC_REGISTER,OS_ADDR);
  374. location.register:=rg.getaddressregister(exprasmlist);
  375. reference_reset_symbol(href,tstoreddef(ttypenode(tcallparanode(left).left).resulttype.def).get_rtti_label(fullrtti),0);
  376. cg.a_loadaddr_ref_reg(exprasmlist,href,location.register);
  377. end;
  378. {*****************************************************************************
  379. ASSIGNED GENERIC HANDLING
  380. *****************************************************************************}
  381. procedure tcginlinenode.second_Assigned;
  382. var
  383. hreg : tregister;
  384. ptrvalidlabel : tasmlabel;
  385. begin
  386. WriteLN('Entering assigned node!');
  387. secondpass(tcallparanode(left).left);
  388. location_release(exprasmlist,tcallparanode(left).left.location);
  389. hreg := rg.getregisterint(exprasmlist);
  390. if (tcallparanode(left).left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  391. begin
  392. { if pointer is non-nil, and is in register, this directly the value we can use }
  393. cg.a_load_reg_reg(exprasmlist, OS_ADDR, tcallparanode(left).left.location.register, hreg);
  394. end
  395. else
  396. begin
  397. getlabel(ptrvalidlabel);
  398. cg.a_load_const_reg(exprasmlist, OS_INT, 1, hreg);
  399. cg.a_cmp_const_ref_label(exprasmlist, OS_ADDR, OC_NE, 0,
  400. tcallparanode(left).left.location.reference, ptrvalidlabel);
  401. cg.a_load_const_reg(exprasmlist, OS_INT, 0, hreg);
  402. cg.a_label(exprasmlist,ptrvalidlabel);
  403. end;
  404. location.register := hreg;
  405. location_reset(location,LOC_REGISTER,OS_INT);
  406. WriteLn('Exiting assigned node!');
  407. end;
  408. {*****************************************************************************
  409. INCLUDE/EXCLUDE GENERIC HANDLING
  410. *****************************************************************************}
  411. procedure tcginlinenode.second_IncludeExclude;
  412. var
  413. scratch_reg : boolean;
  414. hregister : tregister;
  415. asmop : tasmop;
  416. L : longint;
  417. pushedregs : TMaybesave;
  418. cgop : topcg;
  419. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  420. begin
  421. location_copy(location,left.location);
  422. secondpass(tcallparanode(left).left);
  423. if tcallparanode(tcallparanode(left).right).left.nodetype=ordconstn then
  424. begin
  425. { calculate bit position }
  426. l:=1 shl (tordconstnode(tcallparanode(tcallparanode(left).right).left).value mod 32);
  427. { determine operator }
  428. if inlinenumber=in_include_x_y then
  429. cgop:=OP_OR
  430. else
  431. begin
  432. cgop:=OP_AND;
  433. l:=not(l);
  434. end;
  435. if (tcallparanode(left).left.location.loc=LOC_REFERENCE) then
  436. begin
  437. inc(tcallparanode(left).left.location.reference.offset,
  438. (tordconstnode(tcallparanode(tcallparanode(left).right).left).value div 32)*4);
  439. cg.a_op_const_ref(exprasmlist,cgop,OS_INT,l,tcallparanode(left).left.location.reference);
  440. location_release(exprasmlist,tcallparanode(left).left.location);
  441. end
  442. else
  443. { LOC_CREGISTER }
  444. begin
  445. cg.a_op_const_reg(exprasmlist,cgop,l,tcallparanode(left).left.location.register);
  446. end;
  447. end
  448. else
  449. begin
  450. { generate code for the element to set }
  451. maybe_save(exprasmlist,tcallparanode(tcallparanode(left).right).left.registers32,
  452. tcallparanode(left).left.location,pushedregs);
  453. secondpass(tcallparanode(tcallparanode(left).right).left);
  454. maybe_restore(exprasmlist,tcallparanode(left).left.location,pushedregs);
  455. { determine asm operator }
  456. if inlinenumber=in_include_x_y then
  457. asmop:=A_BTS
  458. else
  459. asmop:=A_BTR;
  460. if tcallparanode(tcallparanode(left).right).left.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  461. { we don't need a mod 32 because this is done automatically }
  462. { by the bts instruction. For proper checking we would }
  463. { note: bts doesn't do any mod'ing, that's why we can also use }
  464. { it for normalsets! (JM) }
  465. { need a cmp and jmp, but this should be done by the }
  466. { type cast code which does range checking if necessary (FK) }
  467. begin
  468. scratch_reg := FALSE;
  469. WriteLn('HELLO!');
  470. hregister := rg.makeregsize(tcallparanode(tcallparanode(left).right).left.location.register,OS_INT);
  471. end
  472. else
  473. begin
  474. scratch_reg := TRUE;
  475. hregister:=cg.get_scratch_reg_int(exprasmlist);
  476. end;
  477. cg.a_load_loc_reg(exprasmlist,tcallparanode(tcallparanode(left).right).left.location,hregister);
  478. if (tcallparanode(left).left.location.loc=LOC_REFERENCE) then
  479. emit_reg_ref(asmop,S_L,hregister,tcallparanode(left).left.location.reference)
  480. else
  481. emit_reg_reg(asmop,S_L,hregister,tcallparanode(left).left.location.register);
  482. if scratch_reg then
  483. cg.free_scratch_reg(exprasmlist,hregister);
  484. end;
  485. end;
  486. {*****************************************************************************
  487. FLOAT GENERIC HANDLING
  488. *****************************************************************************}
  489. {
  490. These routines all call internal RTL routines, so if they are
  491. called here, they give an internal error
  492. }
  493. procedure tcginlinenode.second_pi;
  494. begin
  495. internalerror(20020718);
  496. end;
  497. procedure tcginlinenode.second_arctan_real;
  498. begin
  499. internalerror(20020718);
  500. end;
  501. procedure tcginlinenode.second_abs_real;
  502. begin
  503. internalerror(20020718);
  504. end;
  505. procedure tcginlinenode.second_sqr_real;
  506. begin
  507. internalerror(20020718);
  508. end;
  509. procedure tcginlinenode.second_sqrt_real;
  510. begin
  511. internalerror(20020718);
  512. end;
  513. procedure tcginlinenode.second_ln_real;
  514. begin
  515. internalerror(20020718);
  516. end;
  517. procedure tcginlinenode.second_cos_real;
  518. begin
  519. internalerror(20020718);
  520. end;
  521. procedure tcginlinenode.second_sin_real;
  522. begin
  523. internalerror(20020718);
  524. end;
  525. begin
  526. { cinlinenode:=tcginlinenode;}
  527. end.
  528. {
  529. $Log$
  530. Revision 1.1 2002-07-24 04:07:49 carl
  531. + first revision (incomplete)
  532. }