cg64f32.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  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;
  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,aint(lo(value)),ref);
  192. tmpref := ref;
  193. inc(tmpref.offset,4);
  194. cg.a_load_const_ref(list,OS_32,aint(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,aint(lo(value)),reg.reglo);
  236. cg.a_load_const_reg(list,OS_32,aint(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. cg.a_load_subsetref_reg(list,OS_32,OS_32,tmpsref,destreg.reglo);
  273. inc(tmpsref.ref.offset,4);
  274. cg.a_load_subsetref_reg(list,OS_32,OS_32,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. cg.a_load_reg_subsetref(list,OS_32,OS_32,fromreg.reglo,tmpsref);
  298. inc(tmpsref.ref.offset,4);
  299. cg.a_load_reg_subsetref(list,OS_32,OS_32,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. cg.a_load_const_subsetref(list,OS_32,aint(lo(a)),tmpsref);
  313. inc(tmpsref.ref.offset,4);
  314. cg.a_load_const_subsetref(list,OS_32,aint(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,aint(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,aint(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. { Keep this order of first hi before lo to have
  553. the correct push order for i386 }
  554. cg.a_load_reg_cgpara(list,OS_32,reg.reghi,tmplochi);
  555. cg.a_load_reg_cgpara(list,OS_32,reg.reglo,tmploclo);
  556. tmploclo.done;
  557. tmplochi.done;
  558. end;
  559. procedure tcg64f32.a_load64_const_cgpara(list : TAsmList;value : int64;const paraloc : tcgpara);
  560. var
  561. tmplochi,tmploclo: tcgpara;
  562. begin
  563. tmploclo.init;
  564. tmplochi.init;
  565. splitparaloc64(paraloc,tmploclo,tmplochi);
  566. { Keep this order of first hi before lo to have
  567. the correct push order for i386 }
  568. cg.a_load_const_cgpara(list,OS_32,aint(hi(value)),tmplochi);
  569. cg.a_load_const_cgpara(list,OS_32,aint(lo(value)),tmploclo);
  570. tmploclo.done;
  571. tmplochi.done;
  572. end;
  573. procedure tcg64f32.a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  574. var
  575. tmprefhi,tmpreflo : treference;
  576. tmploclo,tmplochi : tcgpara;
  577. begin
  578. tmploclo.init;
  579. tmplochi.init;
  580. splitparaloc64(paraloc,tmploclo,tmplochi);
  581. tmprefhi:=r;
  582. tmpreflo:=r;
  583. if target_info.endian=endian_big then
  584. inc(tmpreflo.offset,4)
  585. else
  586. inc(tmprefhi.offset,4);
  587. { Keep this order of first hi before lo to have
  588. the correct push order for i386 }
  589. cg.a_load_ref_cgpara(list,OS_32,tmprefhi,tmplochi);
  590. cg.a_load_ref_cgpara(list,OS_32,tmpreflo,tmploclo);
  591. tmploclo.done;
  592. tmplochi.done;
  593. end;
  594. procedure tcg64f32.a_load64_loc_cgpara(list : TAsmList;const l:tlocation;const paraloc : tcgpara);
  595. begin
  596. case l.loc of
  597. LOC_REGISTER,
  598. LOC_CREGISTER :
  599. a_load64_reg_cgpara(list,l.register64,paraloc);
  600. LOC_CONSTANT :
  601. a_load64_const_cgpara(list,l.value64,paraloc);
  602. LOC_CREFERENCE,
  603. LOC_REFERENCE :
  604. a_load64_ref_cgpara(list,l.reference,paraloc);
  605. else
  606. internalerror(200203287);
  607. end;
  608. end;
  609. procedure tcg64f32.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  610. var
  611. tmpref: treference;
  612. begin
  613. if (tcgsize2size[mmsize]<>8) then
  614. internalerror(2009112501);
  615. tg.gettemp(list,8,8,tt_normal,tmpref);
  616. a_load64_reg_ref(list,intreg,tmpref);
  617. cg.a_loadmm_ref_reg(list,mmsize,mmsize,tmpref,mmreg,mms_movescalar);
  618. tg.ungettemp(list,tmpref);
  619. end;
  620. procedure tcg64f32.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  621. var
  622. tmpref: treference;
  623. begin
  624. if (tcgsize2size[mmsize]<>8) then
  625. internalerror(2009112502);
  626. tg.gettemp(list,8,8,tt_normal,tmpref);
  627. cg.a_loadmm_reg_ref(list,mmsize,mmsize,mmreg,tmpref,mms_movescalar);
  628. a_load64_ref_reg(list,tmpref,intreg);
  629. tg.ungettemp(list,tmpref);
  630. end;
  631. procedure tcg64f32.g_rangecheck64(list : TAsmList;const l:tlocation;fromdef,todef:tdef);
  632. var
  633. neglabel,
  634. poslabel,
  635. endlabel: tasmlabel;
  636. hreg : tregister;
  637. hdef : torddef;
  638. opsize : tcgsize;
  639. from_signed,to_signed: boolean;
  640. temploc : tlocation;
  641. begin
  642. from_signed := is_signed(fromdef);
  643. to_signed := is_signed(todef);
  644. if not is_64bit(todef) then
  645. begin
  646. { get the high dword in a register }
  647. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  648. begin
  649. hreg := l.register64.reghi;
  650. end
  651. else
  652. begin
  653. hreg:=cg.getintregister(list,OS_32);
  654. a_load64high_ref_reg(list,l.reference,hreg);
  655. end;
  656. current_asmdata.getjumplabel(poslabel);
  657. { check high dword, must be 0 (for positive numbers) }
  658. cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,0,hreg,poslabel);
  659. { It can also be $ffffffff, but only for negative numbers }
  660. if from_signed and to_signed then
  661. begin
  662. current_asmdata.getjumplabel(neglabel);
  663. cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,-1,hreg,neglabel);
  664. end;
  665. { For all other values we have a range check error }
  666. cg.a_call_name(list,'FPC_RANGEERROR',false);
  667. { if the high dword = 0, the low dword can be considered a }
  668. { simple cardinal }
  669. cg.a_label(list,poslabel);
  670. hdef:=torddef.create(u32bit,0,$ffffffff);
  671. location_copy(temploc,l);
  672. temploc.size:=OS_32;
  673. if (temploc.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  674. (target_info.endian = endian_big) then
  675. begin
  676. inc(temploc.reference.offset,4);
  677. temploc.reference.alignment:=newalignment(temploc.reference.alignment,4);
  678. end;
  679. cg.g_rangecheck(list,temploc,hdef,todef);
  680. hdef.owner.deletedef(hdef);
  681. if from_signed and to_signed then
  682. begin
  683. current_asmdata.getjumplabel(endlabel);
  684. cg.a_jmp_always(list,endlabel);
  685. { if the high dword = $ffffffff, then the low dword (when }
  686. { considered as a longint) must be < 0 }
  687. cg.a_label(list,neglabel);
  688. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  689. begin
  690. hreg := l.register64.reglo;
  691. end
  692. else
  693. begin
  694. hreg:=cg.getintregister(list,OS_32);
  695. a_load64low_ref_reg(list,l.reference,hreg);
  696. end;
  697. { get a new neglabel (JM) }
  698. current_asmdata.getjumplabel(neglabel);
  699. cg.a_cmp_const_reg_label(list,OS_32,OC_LT,0,hreg,neglabel);
  700. cg.a_call_name(list,'FPC_RANGEERROR',false);
  701. { if we get here, the 64bit value lies between }
  702. { longint($80000000) and -1 (JM) }
  703. cg.a_label(list,neglabel);
  704. hdef:=torddef.create(s32bit,int64(longint($80000000)),int64(-1));
  705. location_copy(temploc,l);
  706. temploc.size:=OS_32;
  707. cg.g_rangecheck(list,temploc,hdef,todef);
  708. hdef.owner.deletedef(hdef);
  709. cg.a_label(list,endlabel);
  710. end;
  711. end
  712. else
  713. { todef = 64bit int }
  714. { no 64bit subranges supported, so only a small check is necessary }
  715. { if both are signed or both are unsigned, no problem! }
  716. if (from_signed xor to_signed) and
  717. { also not if the fromdef is unsigned and < 64bit, since that will }
  718. { always fit in a 64bit int (todef is 64bit) }
  719. (from_signed or
  720. (torddef(fromdef).ordtype = u64bit)) then
  721. begin
  722. { in all cases, there is only a problem if the higest bit is set }
  723. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  724. begin
  725. if is_64bit(fromdef) then
  726. begin
  727. hreg := l.register64.reghi;
  728. opsize := OS_32;
  729. end
  730. else
  731. begin
  732. hreg := l.register;
  733. opsize := def_cgsize(fromdef);
  734. end;
  735. end
  736. else
  737. begin
  738. hreg:=cg.getintregister(list,OS_32);
  739. opsize:=OS_32;
  740. if l.size in [OS_64,OS_S64] then
  741. a_load64high_ref_reg(list,l.reference,hreg)
  742. else
  743. cg.a_load_ref_reg(list,l.size,OS_32,l.reference,hreg);
  744. end;
  745. current_asmdata.getjumplabel(poslabel);
  746. cg.a_cmp_const_reg_label(list,opsize,OC_GTE,0,hreg,poslabel);
  747. cg.a_call_name(list,'FPC_RANGEERROR',false);
  748. cg.a_label(list,poslabel);
  749. end;
  750. end;
  751. function tcg64f32.optimize64_op_const_reg(list: TAsmList; var op: topcg; var a : int64; var reg: tregister64): boolean;
  752. var
  753. lowvalue, highvalue : longint;
  754. hreg: tregister;
  755. begin
  756. lowvalue := longint(a);
  757. highvalue:= longint(a shr 32);
  758. { assume it will be optimized out }
  759. optimize64_op_const_reg := true;
  760. case op of
  761. OP_ADD:
  762. begin
  763. if a = 0 then
  764. exit;
  765. end;
  766. OP_AND:
  767. begin
  768. if lowvalue <> -1 then
  769. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  770. if highvalue <> -1 then
  771. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  772. { already emitted correctly }
  773. exit;
  774. end;
  775. OP_OR:
  776. begin
  777. if lowvalue <> 0 then
  778. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  779. if highvalue <> 0 then
  780. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  781. { already emitted correctly }
  782. exit;
  783. end;
  784. OP_SUB:
  785. begin
  786. if a = 0 then
  787. exit;
  788. end;
  789. OP_XOR:
  790. begin
  791. end;
  792. OP_SHL:
  793. begin
  794. if a = 0 then
  795. exit;
  796. { simply clear low-register
  797. and shift the rest and swap
  798. registers.
  799. }
  800. if (a > 31) then
  801. begin
  802. cg.a_load_const_reg(list,OS_32,0,reg.reglo);
  803. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reghi);
  804. { swap the registers }
  805. hreg := reg.reghi;
  806. reg.reghi := reg.reglo;
  807. reg.reglo := hreg;
  808. exit;
  809. end;
  810. end;
  811. OP_SHR:
  812. begin
  813. if a = 0 then exit;
  814. { simply clear high-register
  815. and shift the rest and swap
  816. registers.
  817. }
  818. if (a > 31) then
  819. begin
  820. cg.a_load_const_reg(list,OS_32,0,reg.reghi);
  821. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reglo);
  822. { swap the registers }
  823. hreg := reg.reghi;
  824. reg.reghi := reg.reglo;
  825. reg.reglo := hreg;
  826. exit;
  827. end;
  828. end;
  829. OP_IMUL,OP_MUL:
  830. begin
  831. if a = 1 then exit;
  832. end;
  833. OP_IDIV,OP_DIV:
  834. begin
  835. if a = 1 then exit;
  836. end;
  837. else
  838. internalerror(20020817);
  839. end;
  840. optimize64_op_const_reg := false;
  841. end;
  842. end.