cg64f32.pas 38 KB

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