cg64f32.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generation for 64 bit int
  5. arithmethics on 32 bit processors
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. {# This unit implements the code generation for 64 bit int arithmethics on
  20. 32 bit processors.
  21. }
  22. unit cg64f32;
  23. {$i fpcdefs.inc}
  24. interface
  25. uses
  26. aasmbase,aasmtai,aasmdata,aasmcpu,
  27. cpubase,cpupara,
  28. cgbase,cgobj,parabase,cgutils,
  29. symtype
  30. ;
  31. type
  32. {# Defines all the methods required on 32-bit processors
  33. to handle 64-bit integers.
  34. }
  35. tcg64f32 = class(tcg64)
  36. procedure a_load64_const_ref(list : TAsmList;value : int64;const ref : treference);override;
  37. procedure a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);override;
  38. procedure a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);override;
  39. procedure a_load64_reg_reg(list : TAsmList;regsrc,regdst : tregister64);override;
  40. procedure a_load64_const_reg(list : TAsmList;value: int64;reg : tregister64);override;
  41. procedure a_load64_subsetref_reg(list : TAsmList; const sref: tsubsetreference; destreg: tregister64);override;
  42. procedure a_load64_reg_subsetref(list : TAsmList; fromreg: tregister64; const sref: tsubsetreference);override;
  43. procedure a_load64_const_subsetref(list: TAsmlist; a: int64; const sref: tsubsetreference);override;
  44. procedure a_load64_ref_subsetref(list : TAsmList; const fromref: treference; const sref: tsubsetreference);override;
  45. procedure a_load64_subsetref_subsetref(list: TAsmlist; const fromsref, tosref: tsubsetreference);override;
  46. procedure a_load64_subsetref_ref(list : TAsmList; const sref: tsubsetreference; const destref: treference);override;
  47. procedure a_load64_loc_reg(list : TAsmList;const l : tlocation;reg : tregister64);override;
  48. procedure a_load64_loc_ref(list : TAsmList;const l : tlocation;const ref : treference);override;
  49. procedure a_load64_const_loc(list : TAsmList;value : int64;const l : tlocation);override;
  50. procedure a_load64_reg_loc(list : TAsmList;reg : tregister64;const l : tlocation);override;
  51. procedure a_load64high_reg_ref(list : TAsmList;reg : tregister;const ref : treference);override;
  52. procedure a_load64low_reg_ref(list : TAsmList;reg : tregister;const ref : treference);override;
  53. procedure a_load64high_ref_reg(list : TAsmList;const ref : treference;reg : tregister);override;
  54. procedure a_load64low_ref_reg(list : TAsmList;const ref : treference;reg : tregister);override;
  55. procedure a_load64high_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);override;
  56. procedure a_load64low_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);override;
  57. procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
  58. procedure a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);override;
  59. procedure a_op64_const_loc(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const l: tlocation);override;
  60. procedure a_op64_reg_loc(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64;const l : tlocation);override;
  61. procedure a_op64_loc_reg(list : TAsmList;op:TOpCG;size : tcgsize;const l : tlocation;reg : tregister64);override;
  62. procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
  63. procedure a_load64_reg_cgpara(list : TAsmList;reg : tregister64;const paraloc : tcgpara);override;
  64. procedure a_load64_const_cgpara(list : TAsmList;value : int64;const paraloc : tcgpara);override;
  65. procedure a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);override;
  66. procedure a_load64_loc_cgpara(list : TAsmList;const l : tlocation;const paraloc : tcgpara);override;
  67. procedure a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);override;
  68. procedure a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);override;
  69. {# This routine tries to optimize the a_op64_const_reg operation, by
  70. removing superfluous opcodes. Returns TRUE if normal processing
  71. must continue in op64_const_reg, otherwise, everything is processed
  72. entirely in this routine, by emitting the appropriate 32-bit opcodes.
  73. }
  74. function optimize64_op_const_reg(list: TAsmList; var op: topcg; var a : int64; var reg: tregister64): boolean;override;
  75. procedure g_rangecheck64(list: TAsmList; const l:tlocation;fromdef,todef: tdef); override;
  76. end;
  77. {# Creates a tregister64 record from 2 32 Bit registers. }
  78. function joinreg64(reglo,reghi : tregister) : tregister64;
  79. implementation
  80. uses
  81. globtype,systems,constexp,
  82. verbose,cutils,
  83. symbase,symconst,symdef,symtable,defutil,paramgr,
  84. tgobj,hlcgobj;
  85. {****************************************************************************
  86. Helpers
  87. ****************************************************************************}
  88. function joinreg64(reglo,reghi : tregister) : tregister64;
  89. begin
  90. result.reglo:=reglo;
  91. result.reghi:=reghi;
  92. end;
  93. procedure swap64(var q : int64);
  94. begin
  95. q:=(int64(lo(q)) shl 32) or hi(q);
  96. end;
  97. procedure splitparaloc64(const cgpara:tcgpara;var cgparalo,cgparahi:tcgpara);
  98. var
  99. paraloclo,
  100. paralochi : pcgparalocation;
  101. begin
  102. if not(cgpara.size in [OS_64,OS_S64]) then
  103. internalerror(200408231);
  104. if not assigned(cgpara.location) then
  105. internalerror(200408201);
  106. { init lo/hi para }
  107. cgparahi.reset;
  108. if cgpara.size=OS_S64 then
  109. cgparahi.size:=OS_S32
  110. else
  111. cgparahi.size:=OS_32;
  112. cgparahi.intsize:=4;
  113. cgparahi.alignment:=cgpara.alignment;
  114. paralochi:=cgparahi.add_location;
  115. cgparalo.reset;
  116. cgparalo.size:=OS_32;
  117. cgparalo.intsize:=4;
  118. cgparalo.alignment:=cgpara.alignment;
  119. paraloclo:=cgparalo.add_location;
  120. { 2 parameter fields? }
  121. if assigned(cgpara.location^.next) then
  122. begin
  123. { Order for multiple locations is always
  124. paraloc^ -> high
  125. paraloc^.next -> low }
  126. if (target_info.endian=ENDIAN_BIG) then
  127. begin
  128. { paraloc^ -> high
  129. paraloc^.next -> low }
  130. move(cgpara.location^,paralochi^,sizeof(paralochi^));
  131. move(cgpara.location^.next^,paraloclo^,sizeof(paraloclo^));
  132. end
  133. else
  134. begin
  135. { paraloc^ -> low
  136. paraloc^.next -> high }
  137. move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
  138. move(cgpara.location^.next^,paralochi^,sizeof(paralochi^));
  139. end;
  140. end
  141. else
  142. begin
  143. { single parameter, this can only be in memory }
  144. if cgpara.location^.loc<>LOC_REFERENCE then
  145. internalerror(200408282);
  146. move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
  147. move(cgpara.location^,paralochi^,sizeof(paralochi^));
  148. { for big endian low is at +4, for little endian high }
  149. if target_info.endian = endian_big then
  150. begin
  151. inc(cgparalo.location^.reference.offset,4);
  152. cgparalo.alignment:=newalignment(cgparalo.alignment,4);
  153. end
  154. else
  155. begin
  156. inc(cgparahi.location^.reference.offset,4);
  157. cgparahi.alignment:=newalignment(cgparahi.alignment,4);
  158. end;
  159. end;
  160. { fix size }
  161. paraloclo^.size:=cgparalo.size;
  162. paraloclo^.next:=nil;
  163. paralochi^.size:=cgparahi.size;
  164. paralochi^.next:=nil;
  165. end;
  166. {****************************************************************************
  167. TCG64F32
  168. ****************************************************************************}
  169. procedure tcg64f32.a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);
  170. var
  171. tmpreg: tregister;
  172. tmpref: treference;
  173. begin
  174. if target_info.endian = endian_big then
  175. begin
  176. tmpreg:=reg.reglo;
  177. reg.reglo:=reg.reghi;
  178. reg.reghi:=tmpreg;
  179. end;
  180. cg.a_load_reg_ref(list,OS_32,OS_32,reg.reglo,ref);
  181. tmpref := ref;
  182. inc(tmpref.offset,4);
  183. cg.a_load_reg_ref(list,OS_32,OS_32,reg.reghi,tmpref);
  184. end;
  185. procedure tcg64f32.a_load64_const_ref(list : TAsmList;value : int64;const ref : treference);
  186. var
  187. tmpref: treference;
  188. begin
  189. if target_info.endian = endian_big then
  190. swap64(value);
  191. cg.a_load_const_ref(list,OS_32,longint(lo(value)),ref);
  192. tmpref := ref;
  193. inc(tmpref.offset,4);
  194. cg.a_load_const_ref(list,OS_32,longint(hi(value)),tmpref);
  195. end;
  196. procedure tcg64f32.a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);
  197. var
  198. tmpreg: tregister;
  199. tmpref: treference;
  200. begin
  201. if target_info.endian = endian_big then
  202. begin
  203. tmpreg := reg.reglo;
  204. reg.reglo := reg.reghi;
  205. reg.reghi := tmpreg;
  206. end;
  207. tmpref := ref;
  208. if (tmpref.base=reg.reglo) then
  209. begin
  210. tmpreg:=cg.getaddressregister(list);
  211. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpref.base,tmpreg);
  212. tmpref.base:=tmpreg;
  213. end
  214. else
  215. { this works only for the i386, thus the i386 needs to override }
  216. { this method and this method must be replaced by a more generic }
  217. { implementation FK }
  218. if (tmpref.index=reg.reglo) then
  219. begin
  220. tmpreg:=cg.getaddressregister(list);
  221. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpref.index,tmpreg);
  222. tmpref.index:=tmpreg;
  223. end;
  224. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reglo);
  225. inc(tmpref.offset,4);
  226. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reghi);
  227. end;
  228. procedure tcg64f32.a_load64_reg_reg(list : TAsmList;regsrc,regdst : tregister64);
  229. begin
  230. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  231. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reghi,regdst.reghi);
  232. end;
  233. procedure tcg64f32.a_load64_const_reg(list : TAsmList;value : int64;reg : tregister64);
  234. begin
  235. cg.a_load_const_reg(list,OS_32,longint(lo(value)),reg.reglo);
  236. cg.a_load_const_reg(list,OS_32,longint(hi(value)),reg.reghi);
  237. end;
  238. procedure tcg64f32.a_load64_subsetref_reg(list : TAsmList; const sref: tsubsetreference; destreg: tregister64);
  239. var
  240. tmpreg: tregister;
  241. tmpsref: tsubsetreference;
  242. begin
  243. if (sref.bitindexreg <> NR_NO) or
  244. (sref.bitlen <> 64) then
  245. internalerror(2006082310);
  246. if (sref.startbit = 0) then
  247. begin
  248. a_load64_ref_reg(list,sref.ref,destreg);
  249. exit;
  250. end;
  251. if target_info.endian = endian_big then
  252. begin
  253. tmpreg := destreg.reglo;
  254. destreg.reglo := destreg.reghi;
  255. destreg.reghi := tmpreg;
  256. end;
  257. tmpsref:=sref;
  258. if (tmpsref.ref.base=destreg.reglo) then
  259. begin
  260. tmpreg:=cg.getaddressregister(list);
  261. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpsref.ref.base,tmpreg);
  262. tmpsref.ref.base:=tmpreg;
  263. end
  264. else
  265. if (tmpsref.ref.index=destreg.reglo) then
  266. begin
  267. tmpreg:=cg.getaddressregister(list);
  268. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpsref.ref.index,tmpreg);
  269. tmpsref.ref.index:=tmpreg;
  270. end;
  271. tmpsref.bitlen:=32;
  272. hlcg.a_load_subsetref_reg(list,u32inttype,u32inttype,tmpsref,destreg.reglo);
  273. inc(tmpsref.ref.offset,4);
  274. hlcg.a_load_subsetref_reg(list,u32inttype,u32inttype,tmpsref,destreg.reghi);
  275. end;
  276. procedure tcg64f32.a_load64_reg_subsetref(list : TAsmList; fromreg: tregister64; const sref: tsubsetreference);
  277. var
  278. tmpreg: tregister;
  279. tmpsref: tsubsetreference;
  280. begin
  281. if (sref.bitindexreg <> NR_NO) or
  282. (sref.bitlen <> 64) then
  283. internalerror(2006082311);
  284. if (sref.startbit = 0) then
  285. begin
  286. a_load64_reg_ref(list,fromreg,sref.ref);
  287. exit;
  288. end;
  289. if target_info.endian = endian_big then
  290. begin
  291. tmpreg:=fromreg.reglo;
  292. fromreg.reglo:=fromreg.reghi;
  293. fromreg.reghi:=tmpreg;
  294. end;
  295. tmpsref:=sref;
  296. tmpsref.bitlen:=32;
  297. hlcg.a_load_reg_subsetref(list,u32inttype,u32inttype,fromreg.reglo,tmpsref);
  298. inc(tmpsref.ref.offset,4);
  299. hlcg.a_load_reg_subsetref(list,u32inttype,u32inttype,fromreg.reghi,tmpsref);
  300. end;
  301. procedure tcg64f32.a_load64_const_subsetref(list: TAsmlist; a: int64; const sref: tsubsetreference);
  302. var
  303. tmpsref: tsubsetreference;
  304. begin
  305. if (sref.bitindexreg <> NR_NO) or
  306. (sref.bitlen <> 64) then
  307. internalerror(2006082312);
  308. if target_info.endian = endian_big then
  309. swap64(a);
  310. tmpsref := sref;
  311. tmpsref.bitlen := 32;
  312. hlcg.a_load_const_subsetref(list,u32inttype,longint(lo(a)),tmpsref);
  313. inc(tmpsref.ref.offset,4);
  314. hlcg.a_load_const_subsetref(list,u32inttype,longint(hi(a)),tmpsref);
  315. end;
  316. procedure tcg64f32.a_load64_subsetref_subsetref(list: TAsmlist; const fromsref, tosref: tsubsetreference);
  317. var
  318. tmpreg64 : tregister64;
  319. begin
  320. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  321. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  322. a_load64_subsetref_reg(list,fromsref,tmpreg64);
  323. a_load64_reg_subsetref(list,tmpreg64,tosref);
  324. end;
  325. procedure tcg64f32.a_load64_subsetref_ref(list : TAsmList; const sref: tsubsetreference; const destref: treference);
  326. var
  327. tmpreg64 : tregister64;
  328. begin
  329. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  330. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  331. a_load64_subsetref_reg(list,sref,tmpreg64);
  332. a_load64_reg_ref(list,tmpreg64,destref);
  333. end;
  334. procedure tcg64f32.a_load64_ref_subsetref(list : TAsmList; const fromref: treference; const sref: tsubsetreference);
  335. var
  336. tmpreg64 : tregister64;
  337. begin
  338. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  339. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  340. a_load64_ref_reg(list,fromref,tmpreg64);
  341. a_load64_reg_subsetref(list,tmpreg64,sref);
  342. end;
  343. procedure tcg64f32.a_load64_loc_reg(list : TAsmList;const l : tlocation;reg : tregister64);
  344. begin
  345. case l.loc of
  346. LOC_REFERENCE, LOC_CREFERENCE:
  347. a_load64_ref_reg(list,l.reference,reg);
  348. LOC_REGISTER,LOC_CREGISTER:
  349. a_load64_reg_reg(list,l.register64,reg);
  350. LOC_CONSTANT :
  351. a_load64_const_reg(list,l.value64,reg);
  352. LOC_SUBSETREF, LOC_CSUBSETREF:
  353. a_load64_subsetref_reg(list,l.sref,reg);
  354. else
  355. internalerror(200112292);
  356. end;
  357. end;
  358. procedure tcg64f32.a_load64_loc_ref(list : TAsmList;const l : tlocation;const ref : treference);
  359. begin
  360. case l.loc of
  361. LOC_REGISTER,LOC_CREGISTER:
  362. a_load64_reg_ref(list,l.register64,ref);
  363. LOC_CONSTANT :
  364. a_load64_const_ref(list,l.value64,ref);
  365. LOC_SUBSETREF, LOC_CSUBSETREF:
  366. a_load64_subsetref_ref(list,l.sref,ref);
  367. else
  368. internalerror(200203288);
  369. end;
  370. end;
  371. procedure tcg64f32.a_load64_const_loc(list : TAsmList;value : int64;const l : tlocation);
  372. begin
  373. case l.loc of
  374. LOC_REFERENCE, LOC_CREFERENCE:
  375. a_load64_const_ref(list,value,l.reference);
  376. LOC_REGISTER,LOC_CREGISTER:
  377. a_load64_const_reg(list,value,l.register64);
  378. LOC_SUBSETREF, LOC_CSUBSETREF:
  379. a_load64_const_subsetref(list,value,l.sref);
  380. else
  381. internalerror(200112293);
  382. end;
  383. end;
  384. procedure tcg64f32.a_load64_reg_loc(list : TAsmList;reg : tregister64;const l : tlocation);
  385. begin
  386. case l.loc of
  387. LOC_REFERENCE, LOC_CREFERENCE:
  388. a_load64_reg_ref(list,reg,l.reference);
  389. LOC_REGISTER,LOC_CREGISTER:
  390. a_load64_reg_reg(list,reg,l.register64);
  391. LOC_SUBSETREF, LOC_CSUBSETREF:
  392. a_load64_reg_subsetref(list,reg,l.sref);
  393. LOC_MMREGISTER, LOC_CMMREGISTER:
  394. a_loadmm_intreg64_reg(list,l.size,reg,l.register);
  395. else
  396. internalerror(200112293);
  397. end;
  398. end;
  399. procedure tcg64f32.a_load64high_reg_ref(list : TAsmList;reg : tregister;const ref : treference);
  400. var
  401. tmpref: treference;
  402. begin
  403. if target_info.endian = endian_big then
  404. cg.a_load_reg_ref(list,OS_32,OS_32,reg,ref)
  405. else
  406. begin
  407. tmpref := ref;
  408. inc(tmpref.offset,4);
  409. cg.a_load_reg_ref(list,OS_32,OS_32,reg,tmpref)
  410. end;
  411. end;
  412. procedure tcg64f32.a_load64low_reg_ref(list : TAsmList;reg : tregister;const ref : treference);
  413. var
  414. tmpref: treference;
  415. begin
  416. if target_info.endian = endian_little then
  417. cg.a_load_reg_ref(list,OS_32,OS_32,reg,ref)
  418. else
  419. begin
  420. tmpref := ref;
  421. inc(tmpref.offset,4);
  422. cg.a_load_reg_ref(list,OS_32,OS_32,reg,tmpref)
  423. end;
  424. end;
  425. procedure tcg64f32.a_load64high_ref_reg(list : TAsmList;const ref : treference;reg : tregister);
  426. var
  427. tmpref: treference;
  428. begin
  429. if target_info.endian = endian_big then
  430. cg.a_load_ref_reg(list,OS_32,OS_32,ref,reg)
  431. else
  432. begin
  433. tmpref := ref;
  434. inc(tmpref.offset,4);
  435. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg)
  436. end;
  437. end;
  438. procedure tcg64f32.a_load64low_ref_reg(list : TAsmList;const ref : treference;reg : tregister);
  439. var
  440. tmpref: treference;
  441. begin
  442. if target_info.endian = endian_little then
  443. cg.a_load_ref_reg(list,OS_32,OS_32,ref,reg)
  444. else
  445. begin
  446. tmpref := ref;
  447. inc(tmpref.offset,4);
  448. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg)
  449. end;
  450. end;
  451. procedure tcg64f32.a_load64low_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);
  452. begin
  453. case l.loc of
  454. LOC_REFERENCE,
  455. LOC_CREFERENCE :
  456. a_load64low_ref_reg(list,l.reference,reg);
  457. LOC_REGISTER,
  458. LOC_CREGISTER :
  459. cg.a_load_reg_reg(list,OS_32,OS_32,l.register64.reglo,reg);
  460. LOC_CONSTANT :
  461. cg.a_load_const_reg(list,OS_32,longint(lo(l.value64)),reg);
  462. else
  463. internalerror(200203244);
  464. end;
  465. end;
  466. procedure tcg64f32.a_load64high_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);
  467. begin
  468. case l.loc of
  469. LOC_REFERENCE,
  470. LOC_CREFERENCE :
  471. a_load64high_ref_reg(list,l.reference,reg);
  472. LOC_REGISTER,
  473. LOC_CREGISTER :
  474. cg.a_load_reg_reg(list,OS_32,OS_32,l.register64.reghi,reg);
  475. LOC_CONSTANT :
  476. cg.a_load_const_reg(list,OS_32,longint(hi(l.value64)),reg);
  477. else
  478. internalerror(200203244);
  479. end;
  480. end;
  481. procedure tcg64f32.a_op64_const_loc(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const l: tlocation);
  482. begin
  483. case l.loc of
  484. LOC_REFERENCE, LOC_CREFERENCE:
  485. a_op64_const_ref(list,op,size,value,l.reference);
  486. LOC_REGISTER,LOC_CREGISTER:
  487. a_op64_const_reg(list,op,size,value,l.register64);
  488. else
  489. internalerror(200203292);
  490. end;
  491. end;
  492. procedure tcg64f32.a_op64_reg_loc(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64;const l : tlocation);
  493. begin
  494. case l.loc of
  495. LOC_REFERENCE, LOC_CREFERENCE:
  496. a_op64_reg_ref(list,op,size,reg,l.reference);
  497. LOC_REGISTER,LOC_CREGISTER:
  498. a_op64_reg_reg(list,op,size,reg,l.register64);
  499. else
  500. internalerror(2002032422);
  501. end;
  502. end;
  503. procedure tcg64f32.a_op64_loc_reg(list : TAsmList;op:TOpCG;size : tcgsize;const l : tlocation;reg : tregister64);
  504. begin
  505. case l.loc of
  506. LOC_REFERENCE, LOC_CREFERENCE:
  507. a_op64_ref_reg(list,op,size,l.reference,reg);
  508. LOC_REGISTER,LOC_CREGISTER:
  509. a_op64_reg_reg(list,op,size,l.register64,reg);
  510. LOC_CONSTANT :
  511. a_op64_const_reg(list,op,size,l.value64,reg);
  512. else
  513. internalerror(200203242);
  514. end;
  515. end;
  516. procedure tcg64f32.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  517. var
  518. tempreg: tregister64;
  519. begin
  520. tempreg.reghi:=cg.getintregister(list,OS_32);
  521. tempreg.reglo:=cg.getintregister(list,OS_32);
  522. a_load64_ref_reg(list,ref,tempreg);
  523. a_op64_reg_reg(list,op,size,tempreg,reg);
  524. end;
  525. procedure tcg64f32.a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);
  526. var
  527. tempreg: tregister64;
  528. begin
  529. tempreg.reghi:=cg.getintregister(list,OS_32);
  530. tempreg.reglo:=cg.getintregister(list,OS_32);
  531. a_load64_ref_reg(list,ref,tempreg);
  532. a_op64_reg_reg(list,op,size,reg,tempreg);
  533. a_load64_reg_ref(list,tempreg,ref);
  534. end;
  535. procedure tcg64f32.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  536. var
  537. tempreg: tregister64;
  538. begin
  539. tempreg.reghi:=cg.getintregister(list,OS_32);
  540. tempreg.reglo:=cg.getintregister(list,OS_32);
  541. a_load64_ref_reg(list,ref,tempreg);
  542. a_op64_const_reg(list,op,size,value,tempreg);
  543. a_load64_reg_ref(list,tempreg,ref);
  544. end;
  545. procedure tcg64f32.a_load64_reg_cgpara(list : TAsmList;reg : tregister64;const paraloc : tcgpara);
  546. var
  547. tmplochi,tmploclo: tcgpara;
  548. begin
  549. tmploclo.init;
  550. tmplochi.init;
  551. splitparaloc64(paraloc,tmploclo,tmplochi);
  552. if target_info.endian=endian_big then
  553. begin
  554. { Keep this order of first lo before hi to have
  555. the correct push order for m68k }
  556. cg.a_load_reg_cgpara(list,OS_32,reg.reglo,tmploclo);
  557. cg.a_load_reg_cgpara(list,OS_32,reg.reghi,tmplochi);
  558. end
  559. else
  560. begin
  561. { Keep this order of first hi before lo to have
  562. the correct push order for i386 }
  563. cg.a_load_reg_cgpara(list,OS_32,reg.reghi,tmplochi);
  564. cg.a_load_reg_cgpara(list,OS_32,reg.reglo,tmploclo);
  565. end;
  566. tmploclo.done;
  567. tmplochi.done;
  568. end;
  569. procedure tcg64f32.a_load64_const_cgpara(list : TAsmList;value : int64;const paraloc : tcgpara);
  570. var
  571. tmplochi,tmploclo: tcgpara;
  572. begin
  573. tmploclo.init;
  574. tmplochi.init;
  575. splitparaloc64(paraloc,tmploclo,tmplochi);
  576. if target_info.endian=endian_big then
  577. begin
  578. { Keep this order of first lo before hi to have
  579. the correct push order for m68k }
  580. cg.a_load_const_cgpara(list,OS_32,longint(lo(value)),tmploclo);
  581. cg.a_load_const_cgpara(list,OS_32,longint(hi(value)),tmplochi);
  582. end
  583. else
  584. begin
  585. { Keep this order of first hi before lo to have
  586. the correct push order for i386 }
  587. cg.a_load_const_cgpara(list,OS_32,longint(hi(value)),tmplochi);
  588. cg.a_load_const_cgpara(list,OS_32,longint(lo(value)),tmploclo);
  589. end;
  590. tmploclo.done;
  591. tmplochi.done;
  592. end;
  593. procedure tcg64f32.a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  594. var
  595. tmprefhi,tmpreflo : treference;
  596. tmploclo,tmplochi : tcgpara;
  597. begin
  598. tmploclo.init;
  599. tmplochi.init;
  600. splitparaloc64(paraloc,tmploclo,tmplochi);
  601. tmprefhi:=r;
  602. tmpreflo:=r;
  603. if target_info.endian=endian_big then
  604. begin
  605. { Keep this order of first lo before hi to have
  606. the correct push order for m68k }
  607. inc(tmpreflo.offset,4);
  608. cg.a_load_ref_cgpara(list,OS_32,tmpreflo,tmploclo);
  609. cg.a_load_ref_cgpara(list,OS_32,tmprefhi,tmplochi);
  610. end
  611. else
  612. begin
  613. { Keep this order of first hi before lo to have
  614. the correct push order for i386 }
  615. inc(tmprefhi.offset,4);
  616. cg.a_load_ref_cgpara(list,OS_32,tmprefhi,tmplochi);
  617. cg.a_load_ref_cgpara(list,OS_32,tmpreflo,tmploclo);
  618. end;
  619. tmploclo.done;
  620. tmplochi.done;
  621. end;
  622. procedure tcg64f32.a_load64_loc_cgpara(list : TAsmList;const l:tlocation;const paraloc : tcgpara);
  623. begin
  624. case l.loc of
  625. LOC_REGISTER,
  626. LOC_CREGISTER :
  627. a_load64_reg_cgpara(list,l.register64,paraloc);
  628. LOC_CONSTANT :
  629. a_load64_const_cgpara(list,l.value64,paraloc);
  630. LOC_CREFERENCE,
  631. LOC_REFERENCE :
  632. a_load64_ref_cgpara(list,l.reference,paraloc);
  633. else
  634. internalerror(200203287);
  635. end;
  636. end;
  637. procedure tcg64f32.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  638. var
  639. tmpref: treference;
  640. begin
  641. if (tcgsize2size[mmsize]<>8) then
  642. internalerror(2009112501);
  643. tg.gettemp(list,8,8,tt_normal,tmpref);
  644. a_load64_reg_ref(list,intreg,tmpref);
  645. cg.a_loadmm_ref_reg(list,mmsize,mmsize,tmpref,mmreg,mms_movescalar);
  646. tg.ungettemp(list,tmpref);
  647. end;
  648. procedure tcg64f32.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  649. var
  650. tmpref: treference;
  651. begin
  652. if (tcgsize2size[mmsize]<>8) then
  653. internalerror(2009112502);
  654. tg.gettemp(list,8,8,tt_normal,tmpref);
  655. cg.a_loadmm_reg_ref(list,mmsize,mmsize,mmreg,tmpref,mms_movescalar);
  656. a_load64_ref_reg(list,tmpref,intreg);
  657. tg.ungettemp(list,tmpref);
  658. end;
  659. procedure tcg64f32.g_rangecheck64(list : TAsmList;const l:tlocation;fromdef,todef:tdef);
  660. var
  661. neglabel,
  662. poslabel,
  663. endlabel: tasmlabel;
  664. hreg : tregister;
  665. hdef : torddef;
  666. opsize : tcgsize;
  667. from_signed,to_signed: boolean;
  668. temploc : tlocation;
  669. begin
  670. from_signed := is_signed(fromdef);
  671. to_signed := is_signed(todef);
  672. if not is_64bit(todef) then
  673. begin
  674. { get the high dword in a register }
  675. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  676. begin
  677. hreg := l.register64.reghi;
  678. end
  679. else
  680. begin
  681. hreg:=cg.getintregister(list,OS_32);
  682. a_load64high_ref_reg(list,l.reference,hreg);
  683. end;
  684. current_asmdata.getjumplabel(poslabel);
  685. { check high dword, must be 0 (for positive numbers) }
  686. cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,0,hreg,poslabel);
  687. { It can also be $ffffffff, but only for negative numbers }
  688. if from_signed and to_signed then
  689. begin
  690. current_asmdata.getjumplabel(neglabel);
  691. cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,-1,hreg,neglabel);
  692. end;
  693. { For all other values we have a range check error }
  694. cg.a_call_name(list,'fpc_rangeerror',false);
  695. { if the high dword = 0, the low dword can be considered a }
  696. { simple cardinal }
  697. cg.a_label(list,poslabel);
  698. hdef:=torddef.create(u32bit,0,$ffffffff);
  699. location_copy(temploc,l);
  700. temploc.size:=OS_32;
  701. if (temploc.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  702. (target_info.endian = endian_big) then
  703. begin
  704. inc(temploc.reference.offset,4);
  705. temploc.reference.alignment:=newalignment(temploc.reference.alignment,4);
  706. end;
  707. hlcg.g_rangecheck(list,temploc,hdef,todef);
  708. hdef.owner.deletedef(hdef);
  709. if from_signed and to_signed then
  710. begin
  711. current_asmdata.getjumplabel(endlabel);
  712. cg.a_jmp_always(list,endlabel);
  713. { if the high dword = $ffffffff, then the low dword (when }
  714. { considered as a longint) must be < 0 }
  715. cg.a_label(list,neglabel);
  716. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  717. begin
  718. hreg := l.register64.reglo;
  719. end
  720. else
  721. begin
  722. hreg:=cg.getintregister(list,OS_32);
  723. a_load64low_ref_reg(list,l.reference,hreg);
  724. end;
  725. { get a new neglabel (JM) }
  726. current_asmdata.getjumplabel(neglabel);
  727. cg.a_cmp_const_reg_label(list,OS_32,OC_LT,0,hreg,neglabel);
  728. cg.a_call_name(list,'fpc_rangeerror',false);
  729. { if we get here, the 64bit value lies between }
  730. { longint($80000000) and -1 (JM) }
  731. cg.a_label(list,neglabel);
  732. hdef:=torddef.create(s32bit,int64(longint($80000000)),int64(-1));
  733. location_copy(temploc,l);
  734. temploc.size:=OS_32;
  735. hlcg.g_rangecheck(list,temploc,hdef,todef);
  736. hdef.owner.deletedef(hdef);
  737. cg.a_label(list,endlabel);
  738. end;
  739. end
  740. else
  741. { todef = 64bit int }
  742. { no 64bit subranges supported, so only a small check is necessary }
  743. { if both are signed or both are unsigned, no problem! }
  744. if (from_signed xor to_signed) and
  745. { also not if the fromdef is unsigned and < 64bit, since that will }
  746. { always fit in a 64bit int (todef is 64bit) }
  747. (from_signed or
  748. (torddef(fromdef).ordtype = u64bit)) then
  749. begin
  750. { in all cases, there is only a problem if the higest bit is set }
  751. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  752. begin
  753. if is_64bit(fromdef) then
  754. begin
  755. hreg := l.register64.reghi;
  756. opsize := OS_32;
  757. end
  758. else
  759. begin
  760. hreg := l.register;
  761. opsize := def_cgsize(fromdef);
  762. end;
  763. end
  764. else
  765. begin
  766. hreg:=cg.getintregister(list,OS_32);
  767. opsize:=OS_32;
  768. if l.size in [OS_64,OS_S64] then
  769. a_load64high_ref_reg(list,l.reference,hreg)
  770. else
  771. cg.a_load_ref_reg(list,l.size,OS_32,l.reference,hreg);
  772. end;
  773. current_asmdata.getjumplabel(poslabel);
  774. cg.a_cmp_const_reg_label(list,opsize,OC_GTE,0,hreg,poslabel);
  775. cg.a_call_name(list,'fpc_rangeerror',false);
  776. cg.a_label(list,poslabel);
  777. end;
  778. end;
  779. function tcg64f32.optimize64_op_const_reg(list: TAsmList; var op: topcg; var a : int64; var reg: tregister64): boolean;
  780. var
  781. lowvalue, highvalue : longint;
  782. hreg: tregister;
  783. begin
  784. lowvalue := longint(a);
  785. highvalue:= longint(a shr 32);
  786. { assume it will be optimized out }
  787. optimize64_op_const_reg := true;
  788. case op of
  789. OP_ADD:
  790. begin
  791. if a = 0 then
  792. exit;
  793. end;
  794. OP_AND:
  795. begin
  796. if lowvalue <> -1 then
  797. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  798. if highvalue <> -1 then
  799. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  800. { already emitted correctly }
  801. exit;
  802. end;
  803. OP_OR:
  804. begin
  805. if lowvalue <> 0 then
  806. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  807. if highvalue <> 0 then
  808. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  809. { already emitted correctly }
  810. exit;
  811. end;
  812. OP_SUB:
  813. begin
  814. if a = 0 then
  815. exit;
  816. end;
  817. OP_XOR:
  818. begin
  819. end;
  820. OP_SHL:
  821. begin
  822. if a = 0 then
  823. exit;
  824. { simply clear low-register
  825. and shift the rest and swap
  826. registers.
  827. }
  828. if (a > 31) then
  829. begin
  830. cg.a_load_const_reg(list,OS_32,0,reg.reglo);
  831. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reghi);
  832. { swap the registers }
  833. hreg := reg.reghi;
  834. reg.reghi := reg.reglo;
  835. reg.reglo := hreg;
  836. exit;
  837. end;
  838. end;
  839. OP_SHR:
  840. begin
  841. if a = 0 then exit;
  842. { simply clear high-register
  843. and shift the rest and swap
  844. registers.
  845. }
  846. if (a > 31) then
  847. begin
  848. cg.a_load_const_reg(list,OS_32,0,reg.reghi);
  849. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reglo);
  850. { swap the registers }
  851. hreg := reg.reghi;
  852. reg.reghi := reg.reglo;
  853. reg.reglo := hreg;
  854. exit;
  855. end;
  856. end;
  857. OP_IMUL,OP_MUL:
  858. begin
  859. if a = 1 then exit;
  860. end;
  861. OP_IDIV,OP_DIV:
  862. begin
  863. if a = 1 then exit;
  864. end;
  865. else
  866. internalerror(20020817);
  867. end;
  868. optimize64_op_const_reg := false;
  869. end;
  870. end.