ncgcnv.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Generate assembler for nodes that handle type conversions which are
  4. the same for all (most) processors
  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 ncgcnv;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,ncnv,defutil,defcmp;
  23. type
  24. { tcgtypeconvnode }
  25. tcgtypeconvnode = class(ttypeconvnode)
  26. private
  27. function needs_indirect:boolean;
  28. protected
  29. {$ifdef cpuflags}
  30. { CPUs without flags need a specific implementation of int -> bool }
  31. procedure second_int_to_bool;override;
  32. {$endif cpuflags}
  33. procedure second_int_to_int;override;
  34. procedure second_cstring_to_pchar;override;
  35. procedure second_cstring_to_int;override;
  36. procedure second_string_to_chararray;override;
  37. procedure second_array_to_pointer;override;
  38. procedure second_pointer_to_array;override;
  39. procedure second_char_to_string;override;
  40. procedure second_real_to_real;override;
  41. procedure second_cord_to_pointer;override;
  42. procedure second_proc_to_procvar;override;
  43. procedure second_nil_to_methodprocvar;override;
  44. procedure second_bool_to_int;override;
  45. procedure second_bool_to_bool;override;
  46. procedure second_ansistring_to_pchar;override;
  47. procedure second_class_to_intf;override;
  48. procedure second_char_to_char;override;
  49. procedure second_elem_to_openarray;override;
  50. procedure second_nothing;override;
  51. public
  52. procedure pass_generate_code;override;
  53. end;
  54. tcgasnode = class(tasnode)
  55. procedure pass_generate_code;override;
  56. end;
  57. implementation
  58. uses
  59. cutils,verbose,globtype,globals,
  60. aasmbase,aasmtai,aasmdata,aasmcpu,symconst,symdef,symtable,paramgr,
  61. nutils,ncon,ncal,
  62. cpubase,systems,
  63. procinfo,pass_2,
  64. cgbase,
  65. cgutils,cgobj,hlcgobj,
  66. fmodule,
  67. ncgutil,
  68. tgobj
  69. ;
  70. function tcgtypeconvnode.needs_indirect:boolean;
  71. begin
  72. result:=(tf_supports_packages in target_info.flags) and
  73. (target_info.system in systems_indirect_var_imports) and
  74. (
  75. not assigned(current_module) or
  76. (current_module.globalsymtable<>systemunit)
  77. );
  78. end;
  79. procedure tcgtypeconvnode.second_int_to_int;
  80. var
  81. orgsize,
  82. newsize : tcgsize;
  83. ressize,
  84. leftsize : longint;
  85. begin
  86. newsize:=def_cgsize(resultdef);
  87. { insert range check if not explicit or interally generated conversion }
  88. if (flags*[nf_explicit,nf_internal])=[] then
  89. hlcg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
  90. { is the result size smaller? when typecasting from void
  91. we always reuse the current location, because there is
  92. nothing that we can load in a register }
  93. ressize := resultdef.size;
  94. leftsize := left.resultdef.size;
  95. if ((ressize<>leftsize) or
  96. is_bitpacked_access(left)) and
  97. not is_void(left.resultdef) then
  98. begin
  99. location_copy(location,left.location);
  100. { reuse a loc_reference when the newsize is smaller than
  101. than the original, else load it to a register }
  102. if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  103. (ressize<leftsize) then
  104. begin
  105. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),cpointerdef.getreusable(resultdef),location.reference);
  106. location.size:=newsize;
  107. if (target_info.endian = ENDIAN_BIG) then
  108. begin
  109. inc(location.reference.offset,leftsize-ressize);
  110. location.reference.alignment:=newalignment(location.reference.alignment,leftsize-ressize);
  111. end;
  112. end
  113. {$if not defined(cpu16bitalu) and not defined(cpu8bitalu) and not defined(m68k) and not defined(cpuhighleveltarget)}
  114. { FIXME: reg_cgsize incorrectly identifies m68k as "without subregisters" }
  115. { On targets without 8/16 bit register components, 8/16-bit operations
  116. always adjust high bits of result, see 'maybeadjustresult' method in
  117. respective cgcpu.pas. Therefore 8/16-bit locations are valid as larger
  118. ones (except signed->unsigned, which still needs high bits cleared). }
  119. else if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  120. (tcgsize2size[(reg_cgsize(left.location.register))]=sizeof(aint)) and
  121. (ressize>leftsize) and
  122. (newsize in [OS_32,OS_S32,OS_16,OS_S16]) and
  123. (not is_signed(left.resultdef) or is_signed(resultdef)) then
  124. location.size:=newsize
  125. {$endif}
  126. else
  127. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,false);
  128. end
  129. else
  130. begin
  131. { no special loading is required, reuse current location }
  132. { that's not true, if you go from signed to unsiged or }
  133. { vice versa, you need sign extension/removal if the }
  134. { value is already in a register (at least for archs }
  135. { which don't have 8bit register components etc) (JM) }
  136. location_copy(location,left.location);
  137. location.size:=newsize;
  138. orgsize := def_cgsize(left.resultdef);
  139. if (ressize < sizeof(aint)) and
  140. (location.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  141. (orgsize <> newsize) then
  142. begin
  143. location.register := cg.getintregister(current_asmdata.CurrAsmList,newsize);
  144. location.loc := LOC_REGISTER;
  145. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  146. end
  147. else if location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  148. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),cpointerdef.getreusable(resultdef),location.reference)
  149. {$ifdef cpuhighleveltarget}
  150. { high level targets require the types to be correct in all cases }
  151. else if left.resultdef<>resultdef then
  152. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,false);
  153. {$endif cpuhighleveltarget}
  154. end;
  155. end;
  156. {$ifdef cpuflags}
  157. procedure tcgtypeconvnode.second_int_to_bool;
  158. var
  159. hregister : tregister;
  160. href : treference;
  161. resflags : tresflags;
  162. hlabel : tasmlabel;
  163. newsize : tcgsize;
  164. begin
  165. secondpass(left);
  166. if codegenerror then
  167. exit;
  168. { Explicit typecasts from any ordinal type to a boolean type }
  169. { must not change the ordinal value }
  170. if (nf_explicit in flags) and
  171. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
  172. begin
  173. { overriding methods must be able to know in advance whether this
  174. code path will be taken by checking expectloc, so they can call
  175. the inherited method in that case }
  176. if left.expectloc in [LOC_FLAGS,LOC_JUMP] then
  177. internalerror(2014122901);
  178. location_copy(location,left.location);
  179. newsize:=def_cgsize(resultdef);
  180. { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
  181. if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
  182. ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
  183. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  184. else
  185. location.size:=newsize;
  186. exit;
  187. end;
  188. { though ppc/ppc64 doesn't use the generic code, we need to ifdef here
  189. because the code is included into the powerpc compilers }
  190. {$if defined(POWERPC) or defined(POWERPC64)}
  191. resflags.cr := RS_CR0;
  192. resflags.flag:=F_NE;
  193. {$elseif defined(mips)}
  194. resflags.reg1:=NR_NO;
  195. resflags.reg2:=NR_NO;
  196. resflags.cond:=OC_NONE;
  197. {$else}
  198. { Load left node into flag F_NE/F_E }
  199. resflags:=F_NE;
  200. {$endif defined(POWERPC) or defined(POWERPC64)}
  201. case left.location.loc of
  202. LOC_CREFERENCE,
  203. LOC_REFERENCE :
  204. begin
  205. if left.location.size in [OS_64,OS_S64] then
  206. begin
  207. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  208. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.reference,hregister);
  209. href:=left.location.reference;
  210. inc(href.offset,4);
  211. cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,href,hregister);
  212. end
  213. else
  214. begin
  215. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  216. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,left.location.size,left.location.register,left.location.register);
  217. end;
  218. end;
  219. LOC_FLAGS :
  220. begin
  221. resflags:=left.location.resflags;
  222. end;
  223. LOC_REGISTER,LOC_CREGISTER :
  224. begin
  225. {$ifndef cpu64bitalu}
  226. if left.location.size in [OS_64,OS_S64] then
  227. begin
  228. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  229. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.register64.reglo,hregister);
  230. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reghi,hregister);
  231. end
  232. else
  233. {$endif cpu64bitalu}
  234. begin
  235. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,left.location.size,left.location.register,left.location.register);
  236. end;
  237. end;
  238. LOC_JUMP :
  239. begin
  240. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  241. current_asmdata.getjumplabel(hlabel);
  242. cg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  243. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,1,hregister);
  244. cg.a_jmp_always(current_asmdata.CurrAsmList,hlabel);
  245. cg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  246. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,hregister);
  247. cg.a_label(current_asmdata.CurrAsmList,hlabel);
  248. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,hregister,hregister);
  249. end;
  250. else
  251. internalerror(200311301);
  252. end;
  253. { load flags to register }
  254. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  255. location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
  256. cg.g_flags2reg(current_asmdata.CurrAsmList,location.size,resflags,location.register);
  257. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  258. if (is_cbool(resultdef)) then
  259. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,location.size,location.register,location.register);
  260. end;
  261. {$endif cpuflags}
  262. procedure tcgtypeconvnode.second_cstring_to_pchar;
  263. var
  264. hr : treference;
  265. begin
  266. if left.nodetype<>stringconstn then
  267. internalerror(200601131);
  268. if not is_pchar(resultdef) and not is_pwidechar(resultdef) then
  269. internalerror(2014032802);
  270. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  271. case tstringconstnode(left).cst_type of
  272. cst_conststring :
  273. begin
  274. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  275. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register);
  276. end;
  277. cst_shortstring :
  278. begin
  279. inc(left.location.reference.offset);
  280. location.reference.alignment:=1;
  281. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  282. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register);
  283. end;
  284. cst_widestring,
  285. cst_unicodestring,
  286. cst_ansistring :
  287. begin
  288. if tstringconstnode(left).len=0 then
  289. begin
  290. { FPC_EMPTYCHAR is a widechar -> 2 bytes }
  291. reference_reset(hr,2,[]);
  292. hr.symbol:=current_asmdata.RefAsmSymbol('FPC_EMPTYCHAR',AT_DATA,needs_indirect);
  293. current_module.add_extern_asmsym('FPC_EMPTYCHAR',AB_EXTERNAL,AT_DATA);
  294. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  295. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,cwidechartype,resultdef,hr,location.register);
  296. end
  297. else
  298. begin
  299. location_copy(location,left.location);
  300. end;
  301. end;
  302. cst_longstring:
  303. begin
  304. {!!!!!!!}
  305. internalerror(8888);
  306. end;
  307. else
  308. internalerror(200808241);
  309. end;
  310. end;
  311. procedure tcgtypeconvnode.second_cstring_to_int;
  312. begin
  313. { this can't happen because constants are already processed in
  314. pass 1 }
  315. internalerror(200510013);
  316. end;
  317. procedure tcgtypeconvnode.second_string_to_chararray;
  318. begin
  319. if is_chararray(left.resultdef) then
  320. begin
  321. location_copy(location,left.location);
  322. exit;
  323. end;
  324. { should be handled already in resultdef pass (JM) }
  325. internalerror(200108292);
  326. end;
  327. procedure tcgtypeconvnode.second_array_to_pointer;
  328. begin
  329. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  330. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  331. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register);
  332. end;
  333. procedure tcgtypeconvnode.second_pointer_to_array;
  334. begin
  335. { assume natural alignment, volatility of pointer has no effect on the volatility
  336. of the data it points to }
  337. location_reset_ref(location,LOC_REFERENCE,OS_NO,resultdef.alignment,[]);
  338. case left.location.loc of
  339. LOC_CREGISTER,
  340. LOC_REGISTER :
  341. begin
  342. {$ifdef cpu_uses_separate_address_registers}
  343. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  344. begin
  345. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  346. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  347. left.location.register,location.reference.base);
  348. end
  349. else
  350. {$endif}
  351. hlcg.reference_reset_base(location.reference,left.resultdef,left.location.register,0,location.reference.alignment,location.reference.volatility);
  352. end;
  353. LOC_REFERENCE,
  354. LOC_CREFERENCE,
  355. { tricky type casting of parameters can cause these locations, see tb0593.pp on x86_64-linux }
  356. LOC_SUBSETREG,
  357. LOC_CSUBSETREG,
  358. LOC_SUBSETREF,
  359. LOC_CSUBSETREF:
  360. begin
  361. hlcg.reference_reset_base(location.reference,left.resultdef,
  362. hlcg.getaddressregister(current_asmdata.CurrAsmList,left.resultdef),0,location.reference.alignment,[]);
  363. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,
  364. location.reference.base);
  365. if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  366. location_freetemp(current_asmdata.CurrAsmList,left.location);
  367. end;
  368. LOC_CONSTANT:
  369. begin
  370. location.reference.offset:=left.location.value;
  371. end
  372. else
  373. internalerror(2002032216);
  374. end;
  375. end;
  376. procedure tcgtypeconvnode.second_char_to_string;
  377. var
  378. tmpref: treference;
  379. begin
  380. location_reset_ref(location,LOC_REFERENCE,OS_NO,2,[]);
  381. case tstringdef(resultdef).stringtype of
  382. st_shortstring :
  383. begin
  384. tg.gethltemp(current_asmdata.CurrAsmList,cshortstringtype,256,tt_normal,location.reference);
  385. tmpref:=location.reference;
  386. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,
  387. cpointerdef.getreusable(cshortstringtype),
  388. cpointerdef.getreusable(left.resultdef),tmpref);
  389. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,
  390. tmpref);
  391. location_freetemp(current_asmdata.CurrAsmList,left.location);
  392. end;
  393. { the rest is removed in the resultdef pass and converted to compilerprocs }
  394. else
  395. internalerror(4179);
  396. end;
  397. end;
  398. procedure tcgtypeconvnode.second_real_to_real;
  399. {$ifdef x86}
  400. var
  401. tr: treference;
  402. {$endif x86}
  403. begin
  404. location_reset(location,expectloc,def_cgsize(resultdef));
  405. {$ifdef x86}
  406. { extended types in memory which should be loaded into the sse unit
  407. must be converted by the fpu first, so force them to be loaded into
  408. the fpu }
  409. if (expectloc=LOC_MMREGISTER) and
  410. (left.location.size in [OS_F80,OS_C64]) then
  411. begin
  412. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  413. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  414. { round them down to the proper precision }
  415. tg.gethltemp(current_asmdata.currasmlist,resultdef,resultdef.size,tt_normal,tr);
  416. hlcg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,tr);
  417. location_reset_ref(left.location,LOC_REFERENCE,location.size,tr.alignment,tr.volatility);
  418. left.location.reference:=tr;
  419. left.resultdef:=resultdef;
  420. end;
  421. {$endif x86}
  422. { ARM VFP values are in integer registers when they are function results }
  423. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  424. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  425. case left.location.loc of
  426. LOC_FPUREGISTER,
  427. LOC_CFPUREGISTER:
  428. begin
  429. case expectloc of
  430. LOC_FPUREGISTER:
  431. begin
  432. { on sparc a move from double -> single means from two to one register. }
  433. { On all other platforms it also needs rounding to avoid that }
  434. { single(double_regvar) = double_regvar is true in all cases }
  435. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  436. hlcg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  437. end;
  438. LOC_MMREGISTER:
  439. begin
  440. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  441. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  442. hlcg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register,mms_movescalar);
  443. end
  444. else
  445. internalerror(2003012262);
  446. end;
  447. exit
  448. end;
  449. LOC_CREFERENCE,
  450. LOC_REFERENCE:
  451. begin
  452. if expectloc=LOC_MMREGISTER then
  453. begin
  454. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  455. hlcg.a_loadmm_loc_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location,location.register,mms_movescalar)
  456. end
  457. else
  458. begin
  459. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  460. location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  461. hlcg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  462. end;
  463. location_freetemp(current_asmdata.CurrAsmList,left.location);
  464. end;
  465. LOC_MMREGISTER,
  466. LOC_CMMREGISTER:
  467. begin
  468. case expectloc of
  469. LOC_FPUREGISTER:
  470. begin
  471. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  472. location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  473. hlcg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  474. end;
  475. LOC_MMREGISTER:
  476. begin
  477. location.register:=hlcg.getmmregister(current_asmdata.CurrAsmList,resultdef);
  478. hlcg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register,mms_movescalar);
  479. end;
  480. else
  481. internalerror(2003012261);
  482. end;
  483. end;
  484. else
  485. internalerror(2002032215);
  486. end;
  487. end;
  488. procedure tcgtypeconvnode.second_cord_to_pointer;
  489. begin
  490. { this can't happen because constants are already processed in
  491. pass 1 }
  492. internalerror(47423985);
  493. end;
  494. procedure tcgtypeconvnode.second_proc_to_procvar;
  495. var
  496. href: treference;
  497. tmpreg: tregister;
  498. procvarrectype: trecorddef;
  499. procvarselfname: TIDString;
  500. begin
  501. if tabstractprocdef(resultdef).is_addressonly then
  502. begin
  503. location_reset(location,LOC_REGISTER,def_cgsize(voidcodepointertype));
  504. { only a code pointer? (when taking the address of classtype.method
  505. we also only get a code pointer even though the resultdef is a
  506. procedure of object, and hence is_addressonly would return false)
  507. }
  508. if left.location.size = def_cgsize(voidcodepointertype) then
  509. begin
  510. case left.location.loc of
  511. LOC_REFERENCE,LOC_CREFERENCE:
  512. begin
  513. { the procedure symbol is encoded in reference.symbol -> take address }
  514. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidcodepointertype);
  515. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register);
  516. end;
  517. else
  518. internalerror(2013031501)
  519. end;
  520. end
  521. else
  522. begin
  523. { conversion from a procedure of object/nested procvar to plain procvar }
  524. case left.location.loc of
  525. LOC_REFERENCE,LOC_CREFERENCE:
  526. begin
  527. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  528. { code field is the first one }
  529. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(tprocvardef(tprocdef(left.resultdef).getcopyas(procvardef,pc_normal))),cpointerdef.getreusable(resultdef),left.location.reference);
  530. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,resultdef,resultdef,left.location.reference,location.register);
  531. end;
  532. LOC_REGISTER,LOC_CREGISTER:
  533. begin
  534. if target_info.endian=endian_little then
  535. location.register:=left.location.register
  536. else
  537. location.register:=left.location.registerhi;
  538. end;
  539. else
  540. internalerror(2013031502)
  541. end;
  542. end;
  543. end
  544. else
  545. begin
  546. if not tabstractprocdef(left.resultdef).is_addressonly then
  547. location_copy(location,left.location)
  548. else
  549. begin
  550. { assigning a global function to a nested procvar -> create
  551. tmethodpointer record and set the "frame pointer" to nil }
  552. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  553. internalerror(2013031503);
  554. location_reset_ref(location,LOC_REFERENCE,int_cgsize(resultdef.size),sizeof(pint),[]);
  555. tg.gethltemp(current_asmdata.CurrAsmList,resultdef,resultdef.size,tt_normal,location.reference);
  556. href:=location.reference;
  557. if is_nested_pd(tabstractprocdef(resultdef)) then
  558. begin
  559. procvarrectype:=trecorddef(nestedprocpointertype);
  560. procvarselfname:='parentfp';
  561. end
  562. else
  563. begin
  564. procvarrectype:=trecorddef(methodpointertype);
  565. procvarselfname:='self';
  566. end;
  567. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef),cpointerdef.getreusable(procvarrectype),href);
  568. tmpreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidcodepointertype);
  569. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,tprocdef(left.resultdef),voidcodepointertype,left.location.reference,tmpreg);
  570. hlcg.g_load_reg_field_by_name(current_asmdata.CurrAsmList,voidcodepointertype,trecorddef(procvarrectype),tmpreg,'proc',href);
  571. { setting the frame pointer to nil is not strictly necessary
  572. since the global procedure won't use it, but it can help with
  573. debugging }
  574. hlcg.g_load_const_field_by_name(current_asmdata.CurrAsmList,trecorddef(procvarrectype),0,procvarselfname,href);
  575. end;
  576. end;
  577. end;
  578. procedure Tcgtypeconvnode.second_nil_to_methodprocvar;
  579. begin
  580. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  581. location.registerhi:=hlcg.getaddressregister(current_asmdata.currasmlist,voidpointertype);
  582. hlcg.a_load_const_reg(current_asmdata.currasmlist,voidpointertype,0,location.registerhi);
  583. location.register:=hlcg.getaddressregister(current_asmdata.currasmlist,voidcodepointertype);
  584. hlcg.a_load_const_reg(current_asmdata.currasmlist,voidcodepointertype,0,location.register);
  585. end;
  586. procedure tcgtypeconvnode.second_bool_to_int;
  587. var
  588. newsize: tcgsize;
  589. begin
  590. secondpass(left);
  591. location_copy(location,left.location);
  592. newsize:=def_cgsize(resultdef);
  593. { byte(bytebool) or word(wordbool) or longint(longbool) must be }
  594. { accepted for var parameters and assignments, and must not }
  595. { change the ordinal value or value location. }
  596. { htypechk.valid_for_assign ensures that such locations with a }
  597. { size<sizeof(register) cannot be LOC_CREGISTER (they otherwise }
  598. { could be in case of a plain assignment), and LOC_REGISTER can }
  599. { never be an assignment target. The remaining LOC_REGISTER/ }
  600. { LOC_CREGISTER locations do have to be sign/zero-extended. }
  601. if not(nf_explicit in flags) or
  602. (location.loc in [LOC_FLAGS,LOC_JUMP]) or
  603. { change of size/signedness? Then we have to sign/ }
  604. { zero-extend in case of a loc_(c)register }
  605. ((newsize<>left.location.size) and
  606. ((left.resultdef.size<>resultdef.size) or
  607. not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]))) then
  608. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  609. else
  610. { may differ in sign, e.g. bytebool -> byte }
  611. location.size:=newsize;
  612. end;
  613. procedure tcgtypeconvnode.second_bool_to_bool;
  614. begin
  615. { we can reuse the conversion already available
  616. in bool_to_int to resize the value. But when the
  617. size of the new boolean is smaller we need to calculate
  618. the value as is done in int_to_bool. This is needed because
  619. the bits that define the true status can be outside the limits
  620. of the new size and truncating the register can result in a 0
  621. value }
  622. if (left.expectloc in [LOC_FLAGS,LOC_JUMP]) and
  623. { a cbool must be converted to -1/0 }
  624. not is_cbool(resultdef) then
  625. begin
  626. secondpass(left);
  627. if (left.location.loc <> left.expectloc) then
  628. internalerror(2010081601);
  629. location_copy(location,left.location);
  630. end
  631. else if (resultdef.size=left.resultdef.size) and
  632. (is_cbool(resultdef)=is_cbool(left.resultdef)) then
  633. second_bool_to_int
  634. else
  635. begin
  636. if (resultdef.size<>left.resultdef.size) then
  637. { remove nf_explicit to perform full conversion if boolean sizes are different }
  638. exclude(flags, nf_explicit);
  639. second_int_to_bool;
  640. end;
  641. end;
  642. procedure tcgtypeconvnode.second_ansistring_to_pchar;
  643. var
  644. l1 : tasmlabel;
  645. hr : treference;
  646. begin
  647. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  648. current_asmdata.getjumplabel(l1);
  649. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  650. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,
  651. left.location,location.register);
  652. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,resultdef,OC_NE,0,location.register,l1);
  653. { FPC_EMPTYCHAR is a widechar -> 2 bytes }
  654. reference_reset(hr,2,[]);
  655. hr.symbol:=current_asmdata.RefAsmSymbol('FPC_EMPTYCHAR',AT_DATA,needs_indirect);
  656. current_module.add_extern_asmsym('FPC_EMPTYCHAR',AB_EXTERNAL,AT_DATA);
  657. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,cwidechartype,resultdef,hr,location.register);
  658. hlcg.a_label(current_asmdata.CurrAsmList,l1);
  659. end;
  660. procedure tcgtypeconvnode.second_class_to_intf;
  661. var
  662. l1 : tasmlabel;
  663. hd : tobjectdef;
  664. ImplIntf : TImplementedInterface;
  665. begin
  666. l1:=nil;
  667. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  668. case left.location.loc of
  669. LOC_CREFERENCE,
  670. LOC_REFERENCE:
  671. begin
  672. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  673. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.reference,location.register);
  674. location_freetemp(current_asmdata.CurrAsmList,left.location);
  675. end;
  676. LOC_CREGISTER:
  677. begin
  678. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  679. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  680. end;
  681. LOC_REGISTER:
  682. begin
  683. location.register:=left.location.register;
  684. hlcg.g_ptrtypecast_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,location.register);
  685. end
  686. else
  687. internalerror(121120001);
  688. end;
  689. hd:=tobjectdef(left.resultdef);
  690. while assigned(hd) do
  691. begin
  692. ImplIntf:=find_implemented_interface(hd,tobjectdef(resultdef));
  693. if assigned(ImplIntf) then
  694. begin
  695. case ImplIntf.IType of
  696. etStandard:
  697. begin
  698. current_asmdata.getjumplabel(l1);
  699. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,resultdef,OC_EQ,0,location.register,l1);
  700. hlcg.a_op_const_reg(current_asmdata.CurrAsmList,OP_ADD,resultdef,ImplIntf.ioffset,location.register);
  701. break;
  702. end;
  703. else
  704. internalerror(200802163);
  705. end;
  706. end;
  707. hd:=hd.childof;
  708. end;
  709. if hd=nil then
  710. internalerror(2002081301);
  711. if l1=nil then
  712. internalerror(2013120101);
  713. cg.a_label(current_asmdata.CurrAsmList,l1);
  714. end;
  715. procedure tcgtypeconvnode.second_char_to_char;
  716. begin
  717. internalerror(2007081202);
  718. end;
  719. procedure tcgtypeconvnode.second_elem_to_openarray;
  720. begin
  721. { nothing special to do by default }
  722. second_nothing;
  723. end;
  724. procedure tcgtypeconvnode.second_nothing;
  725. var
  726. newsize : tcgsize;
  727. begin
  728. { we reuse the old value }
  729. location_copy(location,left.location);
  730. { Floats should never be returned as LOC_CONSTANT, do the
  731. moving to memory before the new size is set.
  732. Also when converting from a float to a non-float
  733. move to memory first to prevent
  734. invalid LOC_(C)MM/FPUREGISTER locations }
  735. if (
  736. (resultdef.typ=floatdef) and
  737. (location.loc=LOC_CONSTANT)
  738. ) or
  739. ((resultdef.typ=floatdef) xor (location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER,LOC_CMMREGISTER,LOC_MMREGISTER])) then
  740. hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef);
  741. { but use the new size, but we don't know the size of all arrays }
  742. newsize:=def_cgsize(resultdef);
  743. location.size:=newsize;
  744. end;
  745. {$ifdef TESTOBJEXT2}
  746. procedure tcgtypeconvnode.checkobject;
  747. begin
  748. { no checking by default }
  749. end;
  750. {$endif TESTOBJEXT2}
  751. procedure tcgtypeconvnode.pass_generate_code;
  752. begin
  753. { the boolean routines can be called with LOC_JUMP and
  754. call secondpass themselves in the helper }
  755. if not(convtype in [tc_bool_2_int,tc_bool_2_bool,tc_int_2_bool]) then
  756. begin
  757. secondpass(left);
  758. if codegenerror then
  759. exit;
  760. end;
  761. second_call_helper(convtype);
  762. {$ifdef TESTOBJEXT2}
  763. { Check explicit conversions to objects pointers !! }
  764. if p^.explizit and
  765. (p^.resultdef.typ=pointerdef) and
  766. (tpointerdef(p^.resultdef).definition.typ=objectdef) and not
  767. (tobjectdef(tpointerdef(p^.resultdef).definition).isclass) and
  768. ((tobjectdef(tpointerdef(p^.resultdef).definition).options and oo_hasvmt)<>0) and
  769. (cs_check_range in current_settings.localswitches) then
  770. checkobject;
  771. {$endif TESTOBJEXT2}
  772. end;
  773. procedure tcgasnode.pass_generate_code;
  774. begin
  775. secondpass(call);
  776. location_copy(location,call.location);
  777. end;
  778. begin
  779. ctypeconvnode := tcgtypeconvnode;
  780. casnode := tcgasnode;
  781. end.