ncgcnv.pas 37 KB

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