cg64f32.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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. { For all other values we have a range check error }
  748. cg.a_call_name(list,'fpc_rangeerror',false);
  749. { if the high dword = 0, the low dword can be considered a }
  750. { simple cardinal }
  751. cg.a_label(list,poslabel);
  752. hdef:=torddef.create(u32bit,0,$ffffffff);
  753. location_copy(temploc,l);
  754. temploc.size:=OS_32;
  755. if (temploc.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  756. (target_info.endian = endian_big) then
  757. begin
  758. inc(temploc.reference.offset,4);
  759. temploc.reference.alignment:=newalignment(temploc.reference.alignment,4);
  760. end;
  761. hlcg.g_rangecheck(list,temploc,hdef,todef);
  762. hdef.owner.deletedef(hdef);
  763. if from_signed and to_signed then
  764. begin
  765. current_asmdata.getjumplabel(endlabel);
  766. cg.a_jmp_always(list,endlabel);
  767. { if the high dword = $ffffffff, then the low dword (when }
  768. { considered as a longint) must be < 0 }
  769. cg.a_label(list,neglabel);
  770. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  771. begin
  772. hreg := l.register64.reglo;
  773. end
  774. else
  775. begin
  776. hreg:=cg.getintregister(list,OS_32);
  777. a_load64low_ref_reg(list,l.reference,hreg);
  778. end;
  779. { get a new neglabel (JM) }
  780. current_asmdata.getjumplabel(neglabel);
  781. cg.a_cmp_const_reg_label(list,OS_32,OC_LT,0,hreg,neglabel);
  782. cg.a_call_name(list,'fpc_rangeerror',false);
  783. { if we get here, the 64bit value lies between }
  784. { longint($80000000) and -1 (JM) }
  785. cg.a_label(list,neglabel);
  786. hdef:=torddef.create(s32bit,int64(longint($80000000)),int64(-1));
  787. location_copy(temploc,l);
  788. temploc.size:=OS_32;
  789. hlcg.g_rangecheck(list,temploc,hdef,todef);
  790. hdef.owner.deletedef(hdef);
  791. cg.a_label(list,endlabel);
  792. end;
  793. end
  794. else
  795. { todef = 64bit int }
  796. { no 64bit subranges supported, so only a small check is necessary }
  797. { if both are signed or both are unsigned, no problem! }
  798. if (from_signed xor to_signed) and
  799. { also not if the fromdef is unsigned and < 64bit, since that will }
  800. { always fit in a 64bit int (todef is 64bit) }
  801. (from_signed or
  802. (torddef(fromdef).ordtype = u64bit)) then
  803. begin
  804. { in all cases, there is only a problem if the higest bit is set }
  805. if l.loc in [LOC_REGISTER,LOC_CREGISTER] then
  806. begin
  807. if is_64bit(fromdef) then
  808. begin
  809. hreg := l.register64.reghi;
  810. opsize := OS_32;
  811. end
  812. else
  813. begin
  814. hreg := l.register;
  815. opsize := def_cgsize(fromdef);
  816. end;
  817. end
  818. else
  819. begin
  820. hreg:=cg.getintregister(list,OS_32);
  821. opsize:=OS_32;
  822. if l.size in [OS_64,OS_S64] then
  823. a_load64high_ref_reg(list,l.reference,hreg)
  824. else
  825. cg.a_load_ref_reg(list,l.size,OS_32,l.reference,hreg);
  826. end;
  827. current_asmdata.getjumplabel(poslabel);
  828. cg.a_cmp_const_reg_label(list,opsize,OC_GTE,0,hreg,poslabel);
  829. cg.a_call_name(list,'fpc_rangeerror',false);
  830. cg.a_label(list,poslabel);
  831. end;
  832. end;
  833. function tcg64f32.optimize64_op_const_reg(list: TAsmList; var op: topcg; var a : int64; var reg: tregister64): boolean;
  834. var
  835. lowvalue, highvalue : longint;
  836. hreg: tregister;
  837. begin
  838. lowvalue := longint(a);
  839. highvalue:= longint(a shr 32);
  840. { assume it will be optimized out }
  841. optimize64_op_const_reg := true;
  842. case op of
  843. OP_ADD:
  844. begin
  845. if a = 0 then
  846. exit;
  847. end;
  848. OP_AND:
  849. begin
  850. if lowvalue <> -1 then
  851. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  852. if highvalue <> -1 then
  853. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  854. { already emitted correctly }
  855. exit;
  856. end;
  857. OP_OR:
  858. begin
  859. if lowvalue <> 0 then
  860. cg.a_op_const_reg(list,op,OS_32,lowvalue,reg.reglo);
  861. if highvalue <> 0 then
  862. cg.a_op_const_reg(list,op,OS_32,highvalue,reg.reghi);
  863. { already emitted correctly }
  864. exit;
  865. end;
  866. OP_SUB:
  867. begin
  868. if a = 0 then
  869. exit;
  870. end;
  871. OP_XOR:
  872. begin
  873. end;
  874. OP_SHL:
  875. begin
  876. if a = 0 then
  877. exit;
  878. { simply clear low-register
  879. and shift the rest and swap
  880. registers.
  881. }
  882. if (a > 31) then
  883. begin
  884. cg.a_load_const_reg(list,OS_32,0,reg.reglo);
  885. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reghi);
  886. { swap the registers }
  887. hreg := reg.reghi;
  888. reg.reghi := reg.reglo;
  889. reg.reglo := hreg;
  890. exit;
  891. end;
  892. end;
  893. OP_SHR:
  894. begin
  895. if a = 0 then exit;
  896. { simply clear high-register
  897. and shift the rest and swap
  898. registers.
  899. }
  900. if (a > 31) then
  901. begin
  902. cg.a_load_const_reg(list,OS_32,0,reg.reghi);
  903. cg.a_op_const_reg(list,OP_SHL,OS_32,a mod 32,reg.reglo);
  904. { swap the registers }
  905. hreg := reg.reghi;
  906. reg.reghi := reg.reglo;
  907. reg.reglo := hreg;
  908. exit;
  909. end;
  910. end;
  911. OP_IMUL,OP_MUL:
  912. begin
  913. if a = 1 then exit;
  914. end;
  915. OP_IDIV,OP_DIV:
  916. begin
  917. if a = 1 then exit;
  918. end;
  919. else
  920. internalerror(20020817);
  921. end;
  922. optimize64_op_const_reg := false;
  923. end;
  924. end.