cg64f32.pas 38 KB

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