cgcpu.pas 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the SPARC
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,parabase,
  22. cgbase,cgutils,cgobj,cg64f32,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. cpubase,cpuinfo,
  25. node,symconst,SymType,symdef,
  26. rgcpu;
  27. type
  28. TCgSparc=class(tcg)
  29. protected
  30. function IsSimpleRef(const ref:treference):boolean;
  31. public
  32. procedure init_register_allocators;override;
  33. procedure done_register_allocators;override;
  34. function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
  35. { sparc special, needed by cg64 }
  36. procedure make_simple_ref(list:TAsmList;var ref: treference);
  37. procedure make_simple_ref_sparc(list:TAsmList;var ref: treference;loadaddr : boolean;addrreg : tregister);
  38. procedure handle_load_store(list:TAsmList;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  39. procedure handle_reg_const_reg(list:TAsmList;op:Tasmop;src:tregister;a:tcgint;dst:tregister);
  40. { parameter }
  41. procedure a_load_const_cgpara(list:TAsmList;size:tcgsize;a:tcgint;const paraloc:TCGPara);override;
  42. procedure a_load_ref_cgpara(list:TAsmList;sz:tcgsize;const r:TReference;const paraloc:TCGPara);override;
  43. procedure a_loadaddr_ref_cgpara(list:TAsmList;const r:TReference;const paraloc:TCGPara);override;
  44. procedure a_loadfpu_reg_cgpara(list : TAsmList;size : tcgsize;const r : tregister;const paraloc : TCGPara);override;
  45. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  46. procedure a_call_name(list:TAsmList;const s:string; weak: boolean);override;
  47. procedure a_call_reg(list:TAsmList;Reg:TRegister);override;
  48. { General purpose instructions }
  49. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  50. procedure a_op_const_reg(list:TAsmList;Op:TOpCG;size:tcgsize;a:tcgint;reg:TRegister);override;
  51. procedure a_op_reg_reg(list:TAsmList;Op:TOpCG;size:TCGSize;src, dst:TRegister);override;
  52. procedure a_op_const_reg_reg(list:TAsmList;op:TOpCg;size:tcgsize;a:tcgint;src, dst:tregister);override;
  53. procedure a_op_reg_reg_reg(list:TAsmList;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override;
  54. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  55. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  56. { move instructions }
  57. procedure a_load_const_reg(list:TAsmList;size:tcgsize;a:tcgint;reg:tregister);override;
  58. procedure a_load_const_ref(list:TAsmList;size:tcgsize;a:tcgint;const ref:TReference);override;
  59. procedure a_load_reg_ref(list:TAsmList;FromSize,ToSize:TCgSize;reg:TRegister;const ref:TReference);override;
  60. procedure a_load_ref_reg(list:TAsmList;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);override;
  61. procedure a_load_reg_reg(list:TAsmList;FromSize,ToSize:TCgSize;reg1,reg2:tregister);override;
  62. procedure a_loadaddr_ref_reg(list:TAsmList;const ref:TReference;r:tregister);override;
  63. { fpu move instructions }
  64. procedure a_loadfpu_reg_reg(list:TAsmList;fromsize,tosize:tcgsize;reg1, reg2:tregister);override;
  65. procedure a_loadfpu_ref_reg(list:TAsmList;fromsize,tosize:tcgsize;const ref:TReference;reg:tregister);override;
  66. procedure a_loadfpu_reg_ref(list:TAsmList;fromsize,tosize:tcgsize;reg:tregister;const ref:TReference);override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list:TAsmList;size:tcgsize;cmp_op:topcmp;a:tcgint;reg:tregister;l:tasmlabel);override;
  69. procedure a_cmp_reg_reg_label(list:TAsmList;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override;
  70. procedure a_jmp_always(List:TAsmList;l:TAsmLabel);override;
  71. procedure a_jmp_name(list : TAsmList;const s : string);override;
  72. procedure a_jmp_cond(list:TAsmList;cond:TOpCmp;l:tasmlabel);{ override;}
  73. procedure a_jmp_flags(list:TAsmList;const f:TResFlags;l:tasmlabel);override;
  74. procedure g_flags2reg(list:TAsmList;Size:TCgSize;const f:tresflags;reg:TRegister);override;
  75. procedure g_overflowCheck(List:TAsmList;const Loc:TLocation;def:TDef);override;
  76. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  77. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  78. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  79. procedure g_maybe_got_init(list: TAsmList); override;
  80. procedure g_restore_registers(list:TAsmList);override;
  81. procedure g_save_registers(list : TAsmList);override;
  82. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  83. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);override;
  84. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  85. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  86. procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);override;
  87. { Transform unsupported methods into Internal errors }
  88. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  89. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  90. private
  91. g1_used : boolean;
  92. use_unlimited_pic_mode : boolean;
  93. end;
  94. TCg64Sparc=class(tcg64f32)
  95. private
  96. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean);
  97. public
  98. procedure a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);override;
  99. procedure a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);override;
  100. procedure a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);override;
  101. procedure a_op64_reg_reg(list:TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst:TRegister64);override;
  102. procedure a_op64_const_reg(list:TAsmList;op:TOpCG;size : tcgsize;value:int64;regdst:TRegister64);override;
  103. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  104. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  105. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  106. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  107. end;
  108. procedure create_codegen;
  109. const
  110. TOpCG2AsmOp : array[topcg] of TAsmOp=(
  111. A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_SMUL,A_UMUL,A_NEG,A_NOT,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR,A_NONE,A_NONE
  112. );
  113. TOpCG2AsmOpWithFlags : array[topcg] of TAsmOp=(
  114. A_NONE,A_MOV,A_ADDcc,A_ANDcc,A_UDIVcc,A_SDIVcc,A_SMULcc,A_UMULcc,A_NEG,A_NOT,A_ORcc,A_SRA,A_SLL,A_SRL,A_SUBcc,A_XORcc,A_NONE,A_NONE
  115. );
  116. TOpCmp2AsmCond : array[topcmp] of TAsmCond=(C_NONE,
  117. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A
  118. );
  119. implementation
  120. uses
  121. globals,verbose,systems,cutils,
  122. paramgr,fmodule,
  123. symtable,
  124. tgobj,
  125. procinfo,cpupi;
  126. function TCgSparc.IsSimpleRef(const ref:treference):boolean;
  127. begin
  128. if (ref.base=NR_NO) and (ref.index<>NR_NO) then
  129. InternalError(2002100804);
  130. result :=not(assigned(ref.symbol))and
  131. (((ref.index = NR_NO) and
  132. (ref.offset >= simm13lo) and
  133. (ref.offset <= simm13hi)) or
  134. ((ref.index <> NR_NO) and
  135. (ref.offset = 0)));
  136. end;
  137. procedure tcgsparc.make_simple_ref(list:TAsmList;var ref: treference);
  138. begin
  139. make_simple_ref_sparc(list,ref,false,NR_NO);
  140. end;
  141. procedure tcgsparc.make_simple_ref_sparc(list:TAsmList;var ref: treference;loadaddr : boolean;addrreg : tregister);
  142. var
  143. tmpreg,tmpreg2 : tregister;
  144. tmpref : treference;
  145. need_add_got,need_got_load : boolean;
  146. begin
  147. if loadaddr then
  148. tmpreg:=addrreg
  149. else
  150. tmpreg:=NR_NO;
  151. need_add_got:=false;
  152. need_got_load:=false;
  153. { Be sure to have a base register }
  154. if (ref.base=NR_NO) then
  155. begin
  156. ref.base:=ref.index;
  157. ref.index:=NR_NO;
  158. end;
  159. if (cs_create_pic in current_settings.moduleswitches) and
  160. (tf_pic_uses_got in target_info.flags) and
  161. use_unlimited_pic_mode and
  162. assigned(ref.symbol) then
  163. begin
  164. if not(pi_needs_got in current_procinfo.flags) then
  165. begin
  166. {$ifdef CHECK_PIC}
  167. internalerror(200501161);
  168. {$endif CHECK_PIC}
  169. include(current_procinfo.flags,pi_needs_got);
  170. end;
  171. if current_procinfo.got=NR_NO then
  172. current_procinfo.got:=NR_L7;
  173. need_got_load:=true;
  174. need_add_got:=true;
  175. end;
  176. if (cs_create_pic in current_settings.moduleswitches) and
  177. (tf_pic_uses_got in target_info.flags) and
  178. not use_unlimited_pic_mode and
  179. assigned(ref.symbol) then
  180. begin
  181. if tmpreg=NR_NO then
  182. tmpreg:=GetIntRegister(list,OS_INT);
  183. reference_reset(tmpref,ref.alignment);
  184. tmpref.symbol:=ref.symbol;
  185. tmpref.refaddr:=addr_pic;
  186. if not(pi_needs_got in current_procinfo.flags) then
  187. begin
  188. {$ifdef CHECK_PIC}
  189. internalerror(200501161);
  190. {$endif CHECK_PIC}
  191. include(current_procinfo.flags,pi_needs_got);
  192. end;
  193. if current_procinfo.got=NR_NO then
  194. current_procinfo.got:=NR_L7;
  195. tmpref.index:=current_procinfo.got;
  196. list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
  197. ref.symbol:=nil;
  198. if (ref.index<>NR_NO) then
  199. begin
  200. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
  201. ref.index:=tmpreg;
  202. end
  203. else
  204. begin
  205. if ref.base<>NR_NO then
  206. ref.index:=tmpreg
  207. else
  208. ref.base:=tmpreg;
  209. end;
  210. end;
  211. { When need to use SETHI, do it first }
  212. if assigned(ref.symbol) or
  213. (ref.offset<simm13lo) or
  214. (ref.offset>simm13hi) then
  215. begin
  216. if tmpreg=NR_NO then
  217. tmpreg:=GetIntRegister(list,OS_INT);
  218. reference_reset(tmpref,ref.alignment);
  219. tmpref.symbol:=ref.symbol;
  220. if not need_got_load then
  221. tmpref.offset:=ref.offset;
  222. tmpref.refaddr:=addr_high;
  223. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg));
  224. if (ref.offset=0) and (ref.index=NR_NO) and
  225. (ref.base=NR_NO) and not need_add_got then
  226. begin
  227. ref.refaddr:=addr_low;
  228. end
  229. else
  230. begin
  231. { Load the low part is left }
  232. tmpref.refaddr:=addr_low;
  233. list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg));
  234. if not need_got_load then
  235. ref.offset:=0;
  236. { symbol is loaded }
  237. ref.symbol:=nil;
  238. end;
  239. if need_add_got then
  240. begin
  241. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,current_procinfo.got,tmpreg));
  242. need_add_got:=false;
  243. end;
  244. if need_got_load then
  245. begin
  246. tmpref.refaddr:=addr_no;
  247. tmpref.base:=tmpreg;
  248. tmpref.symbol:=nil;
  249. list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
  250. need_got_load:=false;
  251. if (ref.offset<simm13lo) or
  252. (ref.offset>simm13hi) then
  253. begin
  254. tmpref.symbol:=nil;
  255. tmpref.offset:=ref.offset;
  256. tmpref.base:=tmpreg;
  257. tmpref.refaddr := addr_high;
  258. tmpreg2:=GetIntRegister(list,OS_INT);
  259. a_load_const_reg(list,OS_INT,ref.offset,tmpreg2);
  260. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg2,tmpreg));
  261. ref.offset:=0;
  262. end;
  263. end;
  264. if (ref.index<>NR_NO) then
  265. begin
  266. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
  267. ref.index:=tmpreg;
  268. end
  269. else
  270. begin
  271. if ref.base<>NR_NO then
  272. ref.index:=tmpreg
  273. else
  274. ref.base:=tmpreg;
  275. end;
  276. end;
  277. if need_add_got then
  278. begin
  279. if tmpreg=NR_NO then
  280. tmpreg:=GetIntRegister(list,OS_INT);
  281. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,current_procinfo.got,tmpreg));
  282. ref.base:=tmpreg;
  283. ref.index:=NR_NO;
  284. end;
  285. if need_got_load then
  286. begin
  287. if tmpreg=NR_NO then
  288. tmpreg:=GetIntRegister(list,OS_INT);
  289. list.concat(taicpu.op_ref_reg(A_LD,ref,tmpreg));
  290. ref.base:=tmpreg;
  291. ref.index:=NR_NO;
  292. end;
  293. if (ref.base<>NR_NO) or loadaddr then
  294. begin
  295. if loadaddr then
  296. begin
  297. if ref.index<>NR_NO then
  298. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
  299. ref.base:=tmpreg;
  300. ref.index:=NR_NO;
  301. if ref.offset<>0 then
  302. list.concat(taicpu.op_reg_const_reg(A_ADD,ref.base,ref.offset,tmpreg));
  303. end
  304. else if (ref.index<>NR_NO) and
  305. ((ref.offset<>0) or assigned(ref.symbol)) then
  306. begin
  307. if tmpreg=NR_NO then
  308. tmpreg:=GetIntRegister(list,OS_INT);
  309. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
  310. ref.base:=tmpreg;
  311. ref.index:=NR_NO;
  312. end;
  313. end;
  314. end;
  315. procedure tcgsparc.handle_load_store(list:TAsmList;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  316. begin
  317. make_simple_ref(list,ref);
  318. if isstore then
  319. list.concat(taicpu.op_reg_ref(op,reg,ref))
  320. else
  321. list.concat(taicpu.op_ref_reg(op,ref,reg));
  322. end;
  323. procedure tcgsparc.handle_reg_const_reg(list:TAsmList;op:Tasmop;src:tregister;a:tcgint;dst:tregister);
  324. var
  325. tmpreg : tregister;
  326. begin
  327. if (a<simm13lo) or
  328. (a>simm13hi) then
  329. begin
  330. if g1_used then
  331. tmpreg:=GetIntRegister(list,OS_INT)
  332. else
  333. begin
  334. tmpreg:=NR_G1;
  335. g1_used:=true;
  336. end;
  337. a_load_const_reg(list,OS_INT,a,tmpreg);
  338. list.concat(taicpu.op_reg_reg_reg(op,src,tmpreg,dst));
  339. if tmpreg=NR_G1 then
  340. g1_used:=false;
  341. end
  342. else
  343. list.concat(taicpu.op_reg_const_reg(op,src,a,dst));
  344. end;
  345. {****************************************************************************
  346. Assembler code
  347. ****************************************************************************}
  348. procedure Tcgsparc.init_register_allocators;
  349. begin
  350. inherited init_register_allocators;
  351. if (cs_create_pic in current_settings.moduleswitches) and
  352. assigned(current_procinfo) and
  353. (pi_needs_got in current_procinfo.flags) then
  354. begin
  355. current_procinfo.got:=NR_L7;
  356. rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD,
  357. [RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5,
  358. RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6],
  359. first_int_imreg,[]);
  360. end
  361. else
  362. rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD,
  363. [RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5,
  364. RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6,RS_L7],
  365. first_int_imreg,[]);
  366. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBFS,
  367. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
  368. RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,
  369. RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,
  370. RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],
  371. first_fpu_imreg,[]);
  372. { needs at least one element for rgobj not to crash }
  373. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  374. [RS_L0],first_mm_imreg,[]);
  375. end;
  376. procedure Tcgsparc.done_register_allocators;
  377. begin
  378. rg[R_INTREGISTER].free;
  379. rg[R_FPUREGISTER].free;
  380. rg[R_MMREGISTER].free;
  381. inherited done_register_allocators;
  382. end;
  383. function tcgsparc.getfpuregister(list:TAsmList;size:Tcgsize):Tregister;
  384. begin
  385. if size=OS_F64 then
  386. result:=rg[R_FPUREGISTER].getregister(list,R_SUBFD)
  387. else
  388. result:=rg[R_FPUREGISTER].getregister(list,R_SUBFS);
  389. end;
  390. procedure TCgSparc.a_load_const_cgpara(list:TAsmList;size:tcgsize;a:tcgint;const paraloc:TCGPara);
  391. var
  392. Ref:TReference;
  393. begin
  394. paraloc.check_simple_location;
  395. paramanager.alloccgpara(list,paraloc);
  396. case paraloc.location^.loc of
  397. LOC_REGISTER,LOC_CREGISTER:
  398. a_load_const_reg(list,size,a,paraloc.location^.register);
  399. LOC_REFERENCE:
  400. begin
  401. { Code conventions need the parameters being allocated in %o6+92 }
  402. with paraloc.location^.Reference do
  403. begin
  404. if (Index=NR_SP) and (Offset<Target_info.first_parm_offset) then
  405. InternalError(2002081104);
  406. reference_reset_base(ref,index,offset,paraloc.alignment);
  407. end;
  408. a_load_const_ref(list,size,a,ref);
  409. end;
  410. else
  411. InternalError(2002122200);
  412. end;
  413. end;
  414. procedure TCgSparc.a_load_ref_cgpara(list:TAsmList;sz:TCgSize;const r:TReference;const paraloc:TCGPara);
  415. var
  416. ref: treference;
  417. tmpreg:TRegister;
  418. begin
  419. paraloc.check_simple_location;
  420. paramanager.alloccgpara(list,paraloc);
  421. with paraloc.location^ do
  422. begin
  423. case loc of
  424. LOC_REGISTER,LOC_CREGISTER :
  425. a_load_ref_reg(list,sz,paraloc.location^.size,r,Register);
  426. LOC_REFERENCE:
  427. begin
  428. { Code conventions need the parameters being allocated in %o6+92 }
  429. with Reference do
  430. begin
  431. if (Index=NR_SP) and (Offset<Target_info.first_parm_offset) then
  432. InternalError(2002081104);
  433. reference_reset_base(ref,index,offset,paraloc.alignment);
  434. end;
  435. if g1_used then
  436. tmpreg:=GetIntRegister(list,OS_INT)
  437. else
  438. begin
  439. tmpreg:=NR_G1;
  440. g1_used:=true;
  441. end;
  442. a_load_ref_reg(list,sz,sz,r,tmpreg);
  443. a_load_reg_ref(list,sz,sz,tmpreg,ref);
  444. if tmpreg=NR_G1 then
  445. g1_used:=false;
  446. end;
  447. else
  448. internalerror(2002081103);
  449. end;
  450. end;
  451. end;
  452. procedure TCgSparc.a_loadaddr_ref_cgpara(list:TAsmList;const r:TReference;const paraloc:TCGPara);
  453. var
  454. Ref:TReference;
  455. TmpReg:TRegister;
  456. begin
  457. paraloc.check_simple_location;
  458. paramanager.alloccgpara(list,paraloc);
  459. with paraloc.location^ do
  460. begin
  461. case loc of
  462. LOC_REGISTER,LOC_CREGISTER:
  463. a_loadaddr_ref_reg(list,r,register);
  464. LOC_REFERENCE:
  465. begin
  466. reference_reset(ref,paraloc.alignment);
  467. ref.base := reference.index;
  468. ref.offset := reference.offset;
  469. tmpreg:=GetAddressRegister(list);
  470. a_loadaddr_ref_reg(list,r,tmpreg);
  471. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  472. end;
  473. else
  474. internalerror(2002080701);
  475. end;
  476. end;
  477. end;
  478. procedure tcgsparc.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  479. var
  480. href,href2 : treference;
  481. hloc : pcgparalocation;
  482. begin
  483. href:=ref;
  484. hloc:=paraloc.location;
  485. while assigned(hloc) do
  486. begin
  487. paramanager.allocparaloc(list,hloc);
  488. case hloc^.loc of
  489. LOC_REGISTER,LOC_CREGISTER :
  490. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  491. LOC_REFERENCE :
  492. begin
  493. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,paraloc.alignment);
  494. a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2);
  495. end;
  496. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  497. a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  498. else
  499. internalerror(200408241);
  500. end;
  501. inc(href.offset,tcgsize2size[hloc^.size]);
  502. hloc:=hloc^.next;
  503. end;
  504. end;
  505. procedure tcgsparc.a_loadfpu_reg_cgpara(list : TAsmList;size : tcgsize;const r : tregister;const paraloc : TCGPara);
  506. var
  507. href : treference;
  508. begin
  509. { happens for function result loc }
  510. if paraloc.location^.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  511. begin
  512. paraloc.check_simple_location;
  513. paramanager.allocparaloc(list,paraloc.location);
  514. a_loadfpu_reg_reg(list,size,paraloc.location^.size,r,paraloc.location^.register);
  515. end
  516. else
  517. begin
  518. tg.GetTemp(list,TCGSize2Size[size],TCGSize2Size[size],tt_normal,href);
  519. a_loadfpu_reg_ref(list,size,size,r,href);
  520. a_loadfpu_ref_cgpara(list,size,href,paraloc);
  521. tg.Ungettemp(list,href);
  522. end;
  523. end;
  524. procedure TCgSparc.a_call_name(list:TAsmList;const s:string; weak: boolean);
  525. begin
  526. if not weak then
  527. list.concat(taicpu.op_sym(A_CALL,current_asmdata.RefAsmSymbol(s)))
  528. else
  529. list.concat(taicpu.op_sym(A_CALL,current_asmdata.WeakRefAsmSymbol(s)));
  530. { Delay slot }
  531. list.concat(taicpu.op_none(A_NOP));
  532. end;
  533. procedure TCgSparc.a_call_reg(list:TAsmList;Reg:TRegister);
  534. begin
  535. list.concat(taicpu.op_reg(A_CALL,reg));
  536. { Delay slot }
  537. list.concat(taicpu.op_none(A_NOP));
  538. end;
  539. {********************** load instructions ********************}
  540. procedure TCgSparc.a_load_const_reg(list : TAsmList;size : TCGSize;a : tcgint;reg : TRegister);
  541. begin
  542. { we don't use the set instruction here because it could be evalutated to two
  543. instructions which would cause problems with the delay slot (FK) }
  544. if (a=0) then
  545. list.concat(taicpu.op_reg(A_CLR,reg))
  546. { sethi allows to set the upper 22 bit, so we'll take full advantage of it }
  547. else if (aint(a) and aint($1fff))=0 then
  548. list.concat(taicpu.op_const_reg(A_SETHI,aint(a) shr 10,reg))
  549. else if (a>=simm13lo) and (a<=simm13hi) then
  550. list.concat(taicpu.op_const_reg(A_MOV,a,reg))
  551. else
  552. begin
  553. list.concat(taicpu.op_const_reg(A_SETHI,aint(a) shr 10,reg));
  554. list.concat(taicpu.op_reg_const_reg(A_OR,reg,aint(a) and aint($3ff),reg));
  555. end;
  556. end;
  557. procedure TCgSparc.a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : TReference);
  558. begin
  559. if a=0 then
  560. a_load_reg_ref(list,size,size,NR_G0,ref)
  561. else
  562. inherited a_load_const_ref(list,size,a,ref);
  563. end;
  564. procedure TCgSparc.a_load_reg_ref(list:TAsmList;FromSize,ToSize:TCGSize;reg:tregister;const Ref:TReference);
  565. var
  566. op : tasmop;
  567. begin
  568. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  569. fromsize := tosize;
  570. if (ref.alignment<>0) and
  571. (ref.alignment<tcgsize2size[tosize]) then
  572. begin
  573. a_load_reg_ref_unaligned(list,FromSize,ToSize,reg,ref);
  574. end
  575. else
  576. begin
  577. case tosize of
  578. { signed integer registers }
  579. OS_8,
  580. OS_S8:
  581. Op:=A_STB;
  582. OS_16,
  583. OS_S16:
  584. Op:=A_STH;
  585. OS_32,
  586. OS_S32:
  587. Op:=A_ST;
  588. else
  589. InternalError(2002122100);
  590. end;
  591. handle_load_store(list,true,op,reg,ref);
  592. end;
  593. end;
  594. procedure TCgSparc.a_load_ref_reg(list:TAsmList;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);
  595. var
  596. op : tasmop;
  597. begin
  598. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  599. fromsize := tosize;
  600. if (ref.alignment<>0) and
  601. (ref.alignment<tcgsize2size[fromsize]) then
  602. begin
  603. a_load_ref_reg_unaligned(list,FromSize,ToSize,ref,reg);
  604. end
  605. else
  606. begin
  607. case fromsize of
  608. OS_S8:
  609. Op:=A_LDSB;{Load Signed Byte}
  610. OS_8:
  611. Op:=A_LDUB;{Load Unsigned Byte}
  612. OS_S16:
  613. Op:=A_LDSH;{Load Signed Halfword}
  614. OS_16:
  615. Op:=A_LDUH;{Load Unsigned Halfword}
  616. OS_S32,
  617. OS_32:
  618. Op:=A_LD;{Load Word}
  619. OS_S64,
  620. OS_64:
  621. Op:=A_LDD;{Load a Long Word}
  622. else
  623. InternalError(2002122101);
  624. end;
  625. handle_load_store(list,false,op,reg,ref);
  626. if (fromsize=OS_S8) and
  627. (tosize=OS_16) then
  628. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  629. end;
  630. end;
  631. procedure TCgSparc.a_load_reg_reg(list:TAsmList;fromsize,tosize:tcgsize;reg1,reg2:tregister);
  632. var
  633. instr : taicpu;
  634. begin
  635. if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
  636. ((tcgsize2size[fromsize] = tcgsize2size[tosize]) and
  637. (fromsize <> tosize)) or
  638. { needs to mask out the sign in the top 16 bits }
  639. ((fromsize = OS_S8) and
  640. (tosize = OS_16)) then
  641. case tosize of
  642. OS_8 :
  643. a_op_const_reg_reg(list,OP_AND,tosize,$ff,reg1,reg2);
  644. OS_16 :
  645. begin
  646. list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,16,reg2));
  647. list.concat(taicpu.op_reg_const_reg(A_SRL,reg2,16,reg2));
  648. end;
  649. OS_32,
  650. OS_S32 :
  651. begin
  652. instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2);
  653. list.Concat(instr);
  654. { Notify the register allocator that we have written a move instruction so
  655. it can try to eliminate it. }
  656. add_move_instruction(instr);
  657. end;
  658. OS_S8 :
  659. begin
  660. list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,24,reg2));
  661. list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,24,reg2));
  662. end;
  663. OS_S16 :
  664. begin
  665. list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,16,reg2));
  666. list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,16,reg2));
  667. end;
  668. else
  669. internalerror(2002090901);
  670. end
  671. else
  672. begin
  673. instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2);
  674. list.Concat(instr);
  675. { Notify the register allocator that we have written a move instruction so
  676. it can try to eliminate it. }
  677. add_move_instruction(instr);
  678. end;
  679. end;
  680. procedure TCgSparc.a_loadaddr_ref_reg(list : TAsmList;const ref : TReference;r : tregister);
  681. var
  682. tmpref,href : treference;
  683. hreg,tmpreg,hreg2 : tregister;
  684. need_got,need_got_load : boolean;
  685. begin
  686. href:=ref;
  687. {$ifdef TEST_SIMPLE_SPARC}
  688. make_simple_ref_sparc(list,href,true,r);
  689. {$else}
  690. need_got:=false;
  691. need_got_load:=false;
  692. if (href.base=NR_NO) and (href.index<>NR_NO) then
  693. internalerror(200306171);
  694. if (cs_create_pic in current_settings.moduleswitches) and
  695. (tf_pic_uses_got in target_info.flags) and
  696. use_unlimited_pic_mode and
  697. assigned(ref.symbol) then
  698. begin
  699. if not(pi_needs_got in current_procinfo.flags) then
  700. begin
  701. {$ifdef CHECK_PIC}
  702. internalerror(200501161);
  703. {$endif CHECK_PIC}
  704. include(current_procinfo.flags,pi_needs_got);
  705. end;
  706. if current_procinfo.got=NR_NO then
  707. current_procinfo.got:=NR_L7;
  708. need_got_load:=true;
  709. need_got:=true;
  710. end;
  711. if (cs_create_pic in current_settings.moduleswitches) and
  712. (tf_pic_uses_got in target_info.flags) and
  713. not use_unlimited_pic_mode and
  714. assigned(href.symbol) then
  715. begin
  716. tmpreg:=GetIntRegister(list,OS_ADDR);
  717. reference_reset(tmpref,href.alignment);
  718. tmpref.symbol:=href.symbol;
  719. tmpref.refaddr:=addr_pic;
  720. if not(pi_needs_got in current_procinfo.flags) then
  721. begin
  722. {$ifdef CHECK_PIC}
  723. internalerror(200501161);
  724. {$endif CHECK_PIC}
  725. include(current_procinfo.flags,pi_needs_got);
  726. end;
  727. if current_procinfo.got=NR_NO then
  728. current_procinfo.got:=NR_L7;
  729. tmpref.base:=current_procinfo.got;
  730. list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
  731. href.symbol:=nil;
  732. if (href.index<>NR_NO) then
  733. begin
  734. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,href.index,tmpreg));
  735. href.index:=tmpreg;
  736. end
  737. else
  738. begin
  739. if href.base<>NR_NO then
  740. href.index:=tmpreg
  741. else
  742. href.base:=tmpreg;
  743. end;
  744. end;
  745. { At least big offset (need SETHI), maybe base and maybe index }
  746. if assigned(href.symbol) or
  747. (href.offset<simm13lo) or
  748. (href.offset>simm13hi) then
  749. begin
  750. hreg:=GetAddressRegister(list);
  751. reference_reset(tmpref,href.alignment);
  752. tmpref.symbol := href.symbol;
  753. if not need_got_load then
  754. tmpref.offset := href.offset;
  755. tmpref.refaddr := addr_high;
  756. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg));
  757. { Only the low part is left }
  758. tmpref.refaddr:=addr_low;
  759. list.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg));
  760. if need_got then
  761. begin
  762. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,current_procinfo.got,hreg));
  763. need_got:=false;
  764. end;
  765. if need_got_load then
  766. begin
  767. tmpref.symbol:=nil;
  768. tmpref.base:=hreg;
  769. tmpref.refaddr:=addr_no;
  770. list.concat(taicpu.op_ref_reg(A_LD,tmpref,hreg));
  771. need_got_load:=false;
  772. if (href.offset<simm13lo) or
  773. (href.offset>simm13hi) then
  774. begin
  775. tmpref.symbol:=nil;
  776. tmpref.offset:=href.offset;
  777. tmpref.refaddr := addr_high;
  778. hreg2:=GetIntRegister(list,OS_INT);
  779. a_load_const_reg(list,OS_INT,href.offset,hreg2);
  780. { Only the low part is left }
  781. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,hreg2,hreg));
  782. end
  783. else if (href.offset<>0) then
  784. begin
  785. list.concat(taicpu.op_reg_const_reg(A_ADD,hreg,href.offset,hreg));
  786. end;
  787. end;
  788. if href.base<>NR_NO then
  789. begin
  790. if href.index<>NR_NO then
  791. begin
  792. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.base,hreg));
  793. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.index,r));
  794. end
  795. else
  796. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.base,r));
  797. end
  798. else
  799. begin
  800. if hreg<>r then
  801. a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,r);
  802. end;
  803. end
  804. else
  805. { At least small offset, maybe base and maybe index }
  806. if href.offset<>0 then
  807. begin
  808. if href.base<>NR_NO then
  809. begin
  810. if href.index<>NR_NO then
  811. begin
  812. hreg:=GetAddressRegister(list);
  813. list.concat(taicpu.op_reg_const_reg(A_ADD,href.base,href.offset,hreg));
  814. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.index,r));
  815. end
  816. else
  817. list.concat(taicpu.op_reg_const_reg(A_ADD,href.base,href.offset,r));
  818. end
  819. else
  820. list.concat(taicpu.op_const_reg(A_MOV,href.offset,r));
  821. end
  822. else
  823. { Both base and index }
  824. if href.index<>NR_NO then
  825. list.concat(taicpu.op_reg_reg_reg(A_ADD,href.base,href.index,r))
  826. else
  827. { Only base }
  828. if href.base<>NR_NO then
  829. a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
  830. else
  831. { only offset, can be generated by absolute }
  832. a_load_const_reg(list,OS_ADDR,href.offset,r);
  833. if need_got then
  834. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,current_procinfo.got,r));
  835. if need_got_load then
  836. list.concat(taicpu.op_reg_reg(A_LD,r,r));
  837. {$endif}
  838. end;
  839. procedure TCgSparc.a_loadfpu_reg_reg(list:TAsmList;fromsize,tosize:tcgsize;reg1, reg2:tregister);
  840. const
  841. FpuMovInstr : Array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  842. ((A_FMOVS,A_FSTOD),(A_FDTOS,A_FMOVD));
  843. var
  844. op: TAsmOp;
  845. instr : taicpu;
  846. begin
  847. op:=fpumovinstr[fromsize,tosize];
  848. instr:=taicpu.op_reg_reg(op,reg1,reg2);
  849. list.Concat(instr);
  850. { Notify the register allocator that we have written a move instruction so
  851. it can try to eliminate it. }
  852. if (op = A_FMOVS) or
  853. (op = A_FMOVD) then
  854. add_move_instruction(instr);
  855. end;
  856. procedure TCgSparc.a_loadfpu_ref_reg(list:TAsmList;fromsize,tosize:tcgsize;const ref:TReference;reg:tregister);
  857. const
  858. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  859. (A_LDF,A_LDDF);
  860. var
  861. tmpreg: tregister;
  862. begin
  863. tmpreg:=NR_NO;
  864. if (fromsize<>tosize) then
  865. begin
  866. tmpreg:=reg;
  867. reg:=getfpuregister(list,fromsize);
  868. end;
  869. handle_load_store(list,false,fpuloadinstr[fromsize],reg,ref);
  870. if (fromsize<>tosize) then
  871. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  872. end;
  873. procedure TCgSparc.a_loadfpu_reg_ref(list:TAsmList;fromsize,tosize:tcgsize;reg:tregister;const ref:TReference);
  874. const
  875. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  876. (A_STF,A_STDF);
  877. var
  878. tmpreg: tregister;
  879. begin
  880. if (fromsize<>tosize) then
  881. begin
  882. tmpreg:=getfpuregister(list,tosize);
  883. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  884. reg:=tmpreg;
  885. end;
  886. handle_load_store(list,true,fpuloadinstr[tosize],reg,ref);
  887. end;
  888. procedure tcgsparc.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  889. const
  890. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  891. begin
  892. if (op in overflowops) and
  893. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  894. a_load_reg_reg(list,OS_32,size,dst,dst);
  895. end;
  896. procedure TCgSparc.a_op_const_reg(list:TAsmList;Op:TOpCG;size:tcgsize;a:tcgint;reg:TRegister);
  897. begin
  898. optimize_op_const(op,a);
  899. case op of
  900. OP_NONE:
  901. exit;
  902. OP_MOVE:
  903. a_load_const_reg(list,size,a,reg);
  904. OP_NEG,OP_NOT:
  905. internalerror(200306011);
  906. else
  907. a_op_const_reg_reg(list,op,size,a,reg,reg);
  908. end;
  909. end;
  910. procedure TCgSparc.a_op_reg_reg(list:TAsmList;Op:TOpCG;size:TCGSize;src, dst:TRegister);
  911. var
  912. a : aint;
  913. begin
  914. Case Op of
  915. OP_NEG :
  916. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],src,dst));
  917. OP_NOT :
  918. begin
  919. case size of
  920. OS_8 :
  921. a:=aint($ffffff00);
  922. OS_16 :
  923. a:=aint($ffff0000);
  924. else
  925. a:=0;
  926. end;
  927. handle_reg_const_reg(list,A_XNOR,src,a,dst);
  928. end;
  929. else
  930. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src,dst));
  931. end;
  932. maybeadjustresult(list,op,size,dst);
  933. end;
  934. procedure TCgSparc.a_op_const_reg_reg(list:TAsmList;op:TOpCg;size:tcgsize;a:tcgint;src, dst:tregister);
  935. var
  936. l: TLocation;
  937. begin
  938. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,l);
  939. end;
  940. procedure TCgSparc.a_op_reg_reg_reg(list:TAsmList;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);
  941. begin
  942. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst));
  943. maybeadjustresult(list,op,size,dst);
  944. end;
  945. procedure tcgsparc.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  946. var
  947. tmpreg1,tmpreg2 : tregister;
  948. begin
  949. ovloc.loc:=LOC_VOID;
  950. optimize_op_const(op,a);
  951. case op of
  952. OP_NONE:
  953. begin
  954. a_load_reg_reg(list,size,size,src,dst);
  955. exit;
  956. end;
  957. OP_MOVE:
  958. begin
  959. a_load_const_reg(list,size,a,dst);
  960. exit;
  961. end;
  962. end;
  963. if setflags then
  964. begin
  965. handle_reg_const_reg(list,TOpCG2AsmOpWithFlags[op],src,a,dst);
  966. case op of
  967. OP_MUL:
  968. begin
  969. tmpreg1:=GetIntRegister(list,OS_INT);
  970. list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1));
  971. list.concat(taicpu.op_reg_reg(A_CMP,NR_G0,tmpreg1));
  972. ovloc.loc:=LOC_FLAGS;
  973. ovloc.resflags:=F_NE;
  974. end;
  975. OP_IMUL:
  976. begin
  977. tmpreg1:=GetIntRegister(list,OS_INT);
  978. tmpreg2:=GetIntRegister(list,OS_INT);
  979. list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1));
  980. list.concat(taicpu.op_reg_const_reg(A_SRA,dst,31,tmpreg2));
  981. list.concat(taicpu.op_reg_reg(A_CMP,tmpreg1,tmpreg2));
  982. ovloc.loc:=LOC_FLAGS;
  983. ovloc.resflags:=F_NE;
  984. end;
  985. end;
  986. end
  987. else
  988. handle_reg_const_reg(list,TOpCG2AsmOp[op],src,a,dst);
  989. maybeadjustresult(list,op,size,dst);
  990. end;
  991. procedure tcgsparc.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  992. var
  993. tmpreg1,tmpreg2 : tregister;
  994. begin
  995. ovloc.loc:=LOC_VOID;
  996. if setflags then
  997. begin
  998. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOpWithFlags[op],src2,src1,dst));
  999. case op of
  1000. OP_MUL:
  1001. begin
  1002. tmpreg1:=GetIntRegister(list,OS_INT);
  1003. list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1));
  1004. list.concat(taicpu.op_reg_reg(A_CMP,NR_G0,tmpreg1));
  1005. ovloc.loc:=LOC_FLAGS;
  1006. ovloc.resflags:=F_NE;
  1007. end;
  1008. OP_IMUL:
  1009. begin
  1010. tmpreg1:=GetIntRegister(list,OS_INT);
  1011. tmpreg2:=GetIntRegister(list,OS_INT);
  1012. list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1));
  1013. list.concat(taicpu.op_reg_const_reg(A_SRL,dst,31,tmpreg2));
  1014. list.concat(taicpu.op_reg_reg(A_CMP,tmpreg1,tmpreg2));
  1015. ovloc.loc:=LOC_FLAGS;
  1016. ovloc.resflags:=F_NE;
  1017. end;
  1018. end;
  1019. end
  1020. else
  1021. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst));
  1022. maybeadjustresult(list,op,size,dst);
  1023. end;
  1024. {*************** compare instructructions ****************}
  1025. procedure TCgSparc.a_cmp_const_reg_label(list:TAsmList;size:tcgsize;cmp_op:topcmp;a:tcgint;reg:tregister;l:tasmlabel);
  1026. begin
  1027. if (a=0) then
  1028. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg,NR_G0,NR_G0))
  1029. else
  1030. handle_reg_const_reg(list,A_SUBcc,reg,a,NR_G0);
  1031. a_jmp_cond(list,cmp_op,l);
  1032. end;
  1033. procedure TCgSparc.a_cmp_reg_reg_label(list:TAsmList;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);
  1034. begin
  1035. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg2,reg1,NR_G0));
  1036. a_jmp_cond(list,cmp_op,l);
  1037. end;
  1038. procedure TCgSparc.a_jmp_always(List:TAsmList;l:TAsmLabel);
  1039. begin
  1040. List.Concat(TAiCpu.op_sym(A_BA,current_asmdata.RefAsmSymbol(l.name)));
  1041. { Delay slot }
  1042. list.Concat(TAiCpu.Op_none(A_NOP));
  1043. end;
  1044. procedure tcgsparc.a_jmp_name(list : TAsmList;const s : string);
  1045. begin
  1046. List.Concat(TAiCpu.op_sym(A_BA,current_asmdata.RefAsmSymbol(s)));
  1047. { Delay slot }
  1048. list.Concat(TAiCpu.Op_none(A_NOP));
  1049. end;
  1050. procedure TCgSparc.a_jmp_cond(list:TAsmList;cond:TOpCmp;l:TAsmLabel);
  1051. var
  1052. ai:TAiCpu;
  1053. begin
  1054. ai:=TAiCpu.Op_sym(A_Bxx,l);
  1055. ai.SetCondition(TOpCmp2AsmCond[cond]);
  1056. list.Concat(ai);
  1057. { Delay slot }
  1058. list.Concat(TAiCpu.Op_none(A_NOP));
  1059. end;
  1060. procedure TCgSparc.a_jmp_flags(list:TAsmList;const f:TResFlags;l:tasmlabel);
  1061. var
  1062. ai : taicpu;
  1063. begin
  1064. ai:=Taicpu.op_sym(A_Bxx,l);
  1065. ai.SetCondition(flags_to_cond(f));
  1066. list.Concat(ai);
  1067. { Delay slot }
  1068. list.Concat(TAiCpu.Op_none(A_NOP));
  1069. end;
  1070. procedure TCgSparc.g_flags2reg(list:TAsmList;Size:TCgSize;const f:tresflags;reg:TRegister);
  1071. var
  1072. hl : tasmlabel;
  1073. begin
  1074. current_asmdata.getjumplabel(hl);
  1075. a_load_const_reg(list,size,1,reg);
  1076. a_jmp_flags(list,f,hl);
  1077. a_load_const_reg(list,size,0,reg);
  1078. a_label(list,hl);
  1079. end;
  1080. procedure tcgsparc.g_overflowCheck(List:TAsmList;const Loc:TLocation;def:TDef);
  1081. var
  1082. l : tlocation;
  1083. begin
  1084. l.loc:=LOC_VOID;
  1085. g_overflowCheck_loc(list,loc,def,l);
  1086. end;
  1087. procedure TCgSparc.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1088. var
  1089. hl : tasmlabel;
  1090. ai:TAiCpu;
  1091. hflags : tresflags;
  1092. begin
  1093. if not(cs_check_overflow in current_settings.localswitches) then
  1094. exit;
  1095. current_asmdata.getjumplabel(hl);
  1096. case ovloc.loc of
  1097. LOC_VOID:
  1098. begin
  1099. if not((def.typ=pointerdef) or
  1100. ((def.typ=orddef) and
  1101. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1102. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1103. begin
  1104. ai:=TAiCpu.Op_sym(A_Bxx,hl);
  1105. ai.SetCondition(C_NO);
  1106. list.Concat(ai);
  1107. { Delay slot }
  1108. list.Concat(TAiCpu.Op_none(A_NOP));
  1109. end
  1110. else
  1111. a_jmp_cond(list,OC_AE,hl);
  1112. end;
  1113. LOC_FLAGS:
  1114. begin
  1115. hflags:=ovloc.resflags;
  1116. inverse_flags(hflags);
  1117. cg.a_jmp_flags(list,hflags,hl);
  1118. end;
  1119. else
  1120. internalerror(200409281);
  1121. end;
  1122. a_call_name(list,'FPC_OVERFLOW',false);
  1123. a_label(list,hl);
  1124. end;
  1125. { *********** entry/exit code and address loading ************ }
  1126. procedure TCgSparc.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1127. begin
  1128. if nostackframe then
  1129. exit;
  1130. { Althogh the SPARC architecture require only word alignment, software
  1131. convention and the operating system require every stack frame to be double word
  1132. aligned }
  1133. LocalSize:=align(LocalSize,8);
  1134. { Execute the SAVE instruction to get a new register window and create a new
  1135. stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state
  1136. before execution of the SAVE instrucion so it is the caller %i6, when the %i6
  1137. after execution of that instruction is the called function stack pointer}
  1138. { constant can be 13 bit signed, since it's negative, size can be max. 4096 }
  1139. if LocalSize>4096 then
  1140. begin
  1141. a_load_const_reg(list,OS_ADDR,-LocalSize,NR_G1);
  1142. g1_used:=true;
  1143. list.concat(Taicpu.Op_reg_reg_reg(A_SAVE,NR_STACK_POINTER_REG,NR_G1,NR_STACK_POINTER_REG));
  1144. g1_used:=false;
  1145. end
  1146. else
  1147. list.concat(Taicpu.Op_reg_const_reg(A_SAVE,NR_STACK_POINTER_REG,-LocalSize,NR_STACK_POINTER_REG));
  1148. end;
  1149. procedure TCgSparc.g_maybe_got_init(list : TAsmList);
  1150. var
  1151. ref : treference;
  1152. hl : tasmlabel;
  1153. begin
  1154. if (cs_create_pic in current_settings.moduleswitches) and
  1155. (pi_needs_got in current_procinfo.flags) then
  1156. begin
  1157. current_procinfo.got:=NR_L7;
  1158. current_asmdata.getjumplabel(hl);
  1159. list.concat(taicpu.op_sym(A_CALL,hl));
  1160. { ABI recommends the following sequence:
  1161. 1: call 2f
  1162. sethi %hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
  1163. 2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
  1164. add %l7, %o7, %l7 }
  1165. reference_reset_symbol(ref,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),4,sizeof(pint));
  1166. ref.refaddr:=addr_high;
  1167. list.concat(taicpu.op_ref_reg(A_SETHI,ref,NR_L7));
  1168. cg.a_label(list,hl);
  1169. ref.refaddr:=addr_low;
  1170. ref.offset:=8;
  1171. list.concat(Taicpu.Op_reg_ref_reg(A_OR,NR_L7,ref,NR_L7));
  1172. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_L7,NR_O7,NR_L7));
  1173. end;
  1174. end;
  1175. procedure TCgSparc.g_restore_registers(list:TAsmList);
  1176. begin
  1177. { The sparc port uses the sparc standard calling convetions so this function has no used }
  1178. end;
  1179. procedure TCgSparc.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  1180. var
  1181. hr : treference;
  1182. begin
  1183. if paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef) then
  1184. begin
  1185. reference_reset(hr,sizeof(pint));
  1186. hr.offset:=12;
  1187. hr.refaddr:=addr_full;
  1188. if nostackframe then
  1189. begin
  1190. hr.base:=NR_O7;
  1191. list.concat(taicpu.op_ref_reg(A_JMPL,hr,NR_G0));
  1192. list.concat(Taicpu.op_none(A_NOP))
  1193. end
  1194. else
  1195. begin
  1196. { We use trivial restore in the delay slot of the JMPL instruction, as we
  1197. already set result onto %i0 }
  1198. hr.base:=NR_I7;
  1199. list.concat(taicpu.op_ref_reg(A_JMPL,hr,NR_G0));
  1200. list.concat(Taicpu.op_none(A_RESTORE));
  1201. end;
  1202. end
  1203. else
  1204. begin
  1205. if nostackframe then
  1206. begin
  1207. { Here we need to use RETL instead of RET so it uses %o7 }
  1208. list.concat(Taicpu.op_none(A_RETL));
  1209. list.concat(Taicpu.op_none(A_NOP))
  1210. end
  1211. else
  1212. begin
  1213. { We use trivial restore in the delay slot of the JMPL instruction, as we
  1214. already set result onto %i0 }
  1215. list.concat(Taicpu.op_none(A_RET));
  1216. list.concat(Taicpu.op_none(A_RESTORE));
  1217. end;
  1218. end;
  1219. end;
  1220. procedure TCgSparc.g_save_registers(list : TAsmList);
  1221. begin
  1222. { The sparc port uses the sparc standard calling convetions so this function has no used }
  1223. end;
  1224. { ************* concatcopy ************ }
  1225. procedure tcgsparc.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  1226. var
  1227. paraloc1,paraloc2,paraloc3 : TCGPara;
  1228. pd : tprocdef;
  1229. begin
  1230. pd:=search_system_proc('MOVE');
  1231. paraloc1.init;
  1232. paraloc2.init;
  1233. paraloc3.init;
  1234. paramanager.getintparaloc(pd,1,paraloc1);
  1235. paramanager.getintparaloc(pd,2,paraloc2);
  1236. paramanager.getintparaloc(pd,3,paraloc3);
  1237. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  1238. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  1239. a_loadaddr_ref_cgpara(list,source,paraloc1);
  1240. paramanager.freecgpara(list,paraloc3);
  1241. paramanager.freecgpara(list,paraloc2);
  1242. paramanager.freecgpara(list,paraloc1);
  1243. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1244. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1245. a_call_name(list,'FPC_MOVE',false);
  1246. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1247. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1248. paraloc3.done;
  1249. paraloc2.done;
  1250. paraloc1.done;
  1251. end;
  1252. procedure TCgSparc.g_concatcopy(list:TAsmList;const source,dest:treference;len:tcgint);
  1253. var
  1254. tmpreg1,
  1255. hreg,
  1256. countreg: TRegister;
  1257. src, dst: TReference;
  1258. lab: tasmlabel;
  1259. count, count2: aint;
  1260. function reference_is_reusable(const ref: treference): boolean;
  1261. begin
  1262. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1263. (ref.symbol=nil) and
  1264. (ref.offset>=simm13lo) and (ref.offset+len<=simm13hi);
  1265. end;
  1266. begin
  1267. if len>high(longint) then
  1268. internalerror(2002072704);
  1269. { anybody wants to determine a good value here :)? }
  1270. if len>100 then
  1271. g_concatcopy_move(list,source,dest,len)
  1272. else
  1273. begin
  1274. count:=len div 4;
  1275. if (count<=4) and reference_is_reusable(source) then
  1276. src:=source
  1277. else
  1278. begin
  1279. reference_reset_base(src,getintregister(list,OS_ADDR),0,sizeof(aint));
  1280. a_loadaddr_ref_reg(list,source,src.base);
  1281. end;
  1282. if (count<=4) and reference_is_reusable(dest) then
  1283. dst:=dest
  1284. else
  1285. begin
  1286. reference_reset_base(dst,getintregister(list,OS_ADDR),0,sizeof(aint));
  1287. a_loadaddr_ref_reg(list,dest,dst.base);
  1288. end;
  1289. { generate a loop }
  1290. if count>4 then
  1291. begin
  1292. countreg:=GetIntRegister(list,OS_INT);
  1293. tmpreg1:=GetIntRegister(list,OS_INT);
  1294. a_load_const_reg(list,OS_INT,count,countreg);
  1295. current_asmdata.getjumplabel(lab);
  1296. a_label(list, lab);
  1297. list.concat(taicpu.op_ref_reg(A_LD,src,tmpreg1));
  1298. list.concat(taicpu.op_reg_ref(A_ST,tmpreg1,dst));
  1299. list.concat(taicpu.op_reg_const_reg(A_ADD,src.base,4,src.base));
  1300. list.concat(taicpu.op_reg_const_reg(A_ADD,dst.base,4,dst.base));
  1301. list.concat(taicpu.op_reg_const_reg(A_SUBcc,countreg,1,countreg));
  1302. a_jmp_cond(list,OC_NE,lab);
  1303. len := len mod 4;
  1304. end;
  1305. { unrolled loop }
  1306. count:=len div 4;
  1307. if count>0 then
  1308. begin
  1309. tmpreg1:=GetIntRegister(list,OS_INT);
  1310. for count2 := 1 to count do
  1311. begin
  1312. list.concat(taicpu.op_ref_reg(A_LD,src,tmpreg1));
  1313. list.concat(taicpu.op_reg_ref(A_ST,tmpreg1,dst));
  1314. inc(src.offset,4);
  1315. inc(dst.offset,4);
  1316. end;
  1317. len := len mod 4;
  1318. end;
  1319. if (len and 4) <> 0 then
  1320. begin
  1321. hreg:=GetIntRegister(list,OS_INT);
  1322. a_load_ref_reg(list,OS_32,OS_32,src,hreg);
  1323. a_load_reg_ref(list,OS_32,OS_32,hreg,dst);
  1324. inc(src.offset,4);
  1325. inc(dst.offset,4);
  1326. end;
  1327. { copy the leftovers }
  1328. if (len and 2) <> 0 then
  1329. begin
  1330. hreg:=GetIntRegister(list,OS_INT);
  1331. a_load_ref_reg(list,OS_16,OS_16,src,hreg);
  1332. a_load_reg_ref(list,OS_16,OS_16,hreg,dst);
  1333. inc(src.offset,2);
  1334. inc(dst.offset,2);
  1335. end;
  1336. if (len and 1) <> 0 then
  1337. begin
  1338. hreg:=GetIntRegister(list,OS_INT);
  1339. a_load_ref_reg(list,OS_8,OS_8,src,hreg);
  1340. a_load_reg_ref(list,OS_8,OS_8,hreg,dst);
  1341. end;
  1342. end;
  1343. end;
  1344. procedure tcgsparc.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);
  1345. var
  1346. src, dst: TReference;
  1347. tmpreg1,
  1348. countreg: TRegister;
  1349. i : aint;
  1350. lab: tasmlabel;
  1351. begin
  1352. if len>31 then
  1353. g_concatcopy_move(list,source,dest,len)
  1354. else
  1355. begin
  1356. reference_reset(src,source.alignment);
  1357. reference_reset(dst,dest.alignment);
  1358. { load the address of source into src.base }
  1359. src.base:=GetAddressRegister(list);
  1360. a_loadaddr_ref_reg(list,source,src.base);
  1361. { load the address of dest into dst.base }
  1362. dst.base:=GetAddressRegister(list);
  1363. a_loadaddr_ref_reg(list,dest,dst.base);
  1364. { generate a loop }
  1365. if len>4 then
  1366. begin
  1367. countreg:=GetIntRegister(list,OS_INT);
  1368. tmpreg1:=GetIntRegister(list,OS_INT);
  1369. a_load_const_reg(list,OS_INT,len,countreg);
  1370. current_asmdata.getjumplabel(lab);
  1371. a_label(list, lab);
  1372. list.concat(taicpu.op_ref_reg(A_LDUB,src,tmpreg1));
  1373. list.concat(taicpu.op_reg_ref(A_STB,tmpreg1,dst));
  1374. list.concat(taicpu.op_reg_const_reg(A_ADD,src.base,1,src.base));
  1375. list.concat(taicpu.op_reg_const_reg(A_ADD,dst.base,1,dst.base));
  1376. list.concat(taicpu.op_reg_const_reg(A_SUBcc,countreg,1,countreg));
  1377. a_jmp_cond(list,OC_NE,lab);
  1378. end
  1379. else
  1380. begin
  1381. { unrolled loop }
  1382. tmpreg1:=GetIntRegister(list,OS_INT);
  1383. for i:=1 to len do
  1384. begin
  1385. list.concat(taicpu.op_ref_reg(A_LDUB,src,tmpreg1));
  1386. list.concat(taicpu.op_reg_ref(A_STB,tmpreg1,dst));
  1387. inc(src.offset);
  1388. inc(dst.offset);
  1389. end;
  1390. end;
  1391. end;
  1392. end;
  1393. procedure tcgsparc.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1394. var
  1395. make_global : boolean;
  1396. href : treference;
  1397. begin
  1398. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1399. Internalerror(200006137);
  1400. if not assigned(procdef.struct) or
  1401. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1402. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1403. Internalerror(200006138);
  1404. if procdef.owner.symtabletype<>ObjectSymtable then
  1405. Internalerror(200109191);
  1406. make_global:=false;
  1407. if (not current_module.is_unit) or create_smartlink or
  1408. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1409. make_global:=true;
  1410. if make_global then
  1411. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1412. else
  1413. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1414. { set param1 interface to self }
  1415. g_adjust_self_value(list,procdef,ioffset);
  1416. if (po_virtualmethod in procdef.procoptions) and
  1417. not is_objectpascal_helper(procdef.struct) then
  1418. begin
  1419. if (procdef.extnumber=$ffff) then
  1420. Internalerror(200006139);
  1421. { mov 0(%rdi),%rax ; load vmt}
  1422. reference_reset_base(href,NR_O0,0,sizeof(pint));
  1423. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_G1);
  1424. g1_used:=true;
  1425. { jmp *vmtoffs(%eax) ; method offs }
  1426. reference_reset_base(href,NR_G1,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  1427. list.concat(taicpu.op_ref_reg(A_LD,href,NR_G1));
  1428. list.concat(taicpu.op_reg(A_JMP,NR_G1));
  1429. g1_used:=false;
  1430. { Delay slot }
  1431. list.Concat(TAiCpu.Op_none(A_NOP));
  1432. end
  1433. else
  1434. begin
  1435. { Emit a branch, which is PIC-safe, but limited to 8 MByte range on SPARC.
  1436. Since interface wrappers are always located in the same unit with
  1437. their target methods, this limit applies (roughly) to code size of single
  1438. unit, not to entire program. It looks like a reasonable tradeoff.
  1439. If distance limit is ever exceeded, consider changing high-level compiler
  1440. logic to emit wrappers near target methods, not at the end of unit. }
  1441. a_jmp_name(list,procdef.mangledname);
  1442. end;
  1443. List.concat(Tai_symbol_end.Createname(labelname));
  1444. end;
  1445. procedure tcgsparc.g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);
  1446. begin
  1447. { CALL overwrites %o7 with its own address, we use delay slot to restore it. }
  1448. list.concat(taicpu.op_reg_reg(A_MOV,NR_O7,NR_G1));
  1449. list.concat(taicpu.op_sym(A_CALL,current_asmdata.RefAsmSymbol(externalname)));
  1450. list.concat(taicpu.op_reg_reg(A_MOV,NR_G1,NR_O7));
  1451. end;
  1452. procedure tcgsparc.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1453. begin
  1454. Comment(V_Error,'tcgsparc.g_stackpointer_alloc method not implemented');
  1455. end;
  1456. procedure tcgsparc.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1457. begin
  1458. Comment(V_Error,'tcgsparc.a_bit_scan_reg_reg method not implemented');
  1459. end;
  1460. {****************************************************************************
  1461. TCG64Sparc
  1462. ****************************************************************************}
  1463. procedure tcg64sparc.a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);
  1464. var
  1465. tmpref: treference;
  1466. begin
  1467. { Override this function to prevent loading the reference twice }
  1468. tmpref:=ref;
  1469. cg.a_load_reg_ref(list,OS_32,OS_32,reg.reghi,tmpref);
  1470. inc(tmpref.offset,4);
  1471. cg.a_load_reg_ref(list,OS_32,OS_32,reg.reglo,tmpref);
  1472. end;
  1473. procedure tcg64sparc.a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);
  1474. var
  1475. tmpref: treference;
  1476. begin
  1477. { Override this function to prevent loading the reference twice }
  1478. tmpref:=ref;
  1479. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reghi);
  1480. inc(tmpref.offset,4);
  1481. cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reglo);
  1482. end;
  1483. procedure tcg64sparc.a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  1484. var
  1485. hreg64 : tregister64;
  1486. begin
  1487. { Override this function to prevent loading the reference twice.
  1488. Use here some extra registers, but those are optimized away by the RA }
  1489. hreg64.reglo:=cg.GetIntRegister(list,OS_32);
  1490. hreg64.reghi:=cg.GetIntRegister(list,OS_32);
  1491. a_load64_ref_reg(list,r,hreg64);
  1492. a_load64_reg_cgpara(list,hreg64,paraloc);
  1493. end;
  1494. procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean);
  1495. begin
  1496. case op of
  1497. OP_ADD :
  1498. begin
  1499. op1:=A_ADDCC;
  1500. if checkoverflow then
  1501. op2:=A_ADDXCC
  1502. else
  1503. op2:=A_ADDX;
  1504. end;
  1505. OP_SUB :
  1506. begin
  1507. op1:=A_SUBCC;
  1508. if checkoverflow then
  1509. op2:=A_SUBXCC
  1510. else
  1511. op2:=A_SUBX;
  1512. end;
  1513. OP_XOR :
  1514. begin
  1515. op1:=A_XOR;
  1516. op2:=A_XOR;
  1517. end;
  1518. OP_OR :
  1519. begin
  1520. op1:=A_OR;
  1521. op2:=A_OR;
  1522. end;
  1523. OP_AND :
  1524. begin
  1525. op1:=A_AND;
  1526. op2:=A_AND;
  1527. end;
  1528. else
  1529. internalerror(200203241);
  1530. end;
  1531. end;
  1532. procedure TCg64Sparc.a_op64_reg_reg(list:TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst:TRegister64);
  1533. var
  1534. op1,op2 : TAsmOp;
  1535. begin
  1536. case op of
  1537. OP_NEG :
  1538. begin
  1539. { Use the simple code: y=0-z }
  1540. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,NR_G0,regsrc.reglo,regdst.reglo));
  1541. list.concat(taicpu.op_reg_reg_reg(A_SUBX,NR_G0,regsrc.reghi,regdst.reghi));
  1542. exit;
  1543. end;
  1544. OP_NOT :
  1545. begin
  1546. list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reglo,NR_G0,regdst.reglo));
  1547. list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reghi,NR_G0,regdst.reghi));
  1548. exit;
  1549. end;
  1550. end;
  1551. get_64bit_ops(op,op1,op2,false);
  1552. list.concat(taicpu.op_reg_reg_reg(op1,regdst.reglo,regsrc.reglo,regdst.reglo));
  1553. list.concat(taicpu.op_reg_reg_reg(op2,regdst.reghi,regsrc.reghi,regdst.reghi));
  1554. end;
  1555. procedure TCg64Sparc.a_op64_const_reg(list:TAsmList;op:TOpCG;size : tcgsize;value:int64;regdst:TRegister64);
  1556. var
  1557. op1,op2:TAsmOp;
  1558. begin
  1559. case op of
  1560. OP_NEG,
  1561. OP_NOT :
  1562. internalerror(200306017);
  1563. end;
  1564. get_64bit_ops(op,op1,op2,false);
  1565. tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reglo,tcgint(lo(value)),regdst.reglo);
  1566. tcgsparc(cg).handle_reg_const_reg(list,op2,regdst.reghi,tcgint(hi(value)),regdst.reghi);
  1567. end;
  1568. procedure tcg64sparc.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64; regsrc,regdst : tregister64);
  1569. var
  1570. l : tlocation;
  1571. begin
  1572. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,l);
  1573. end;
  1574. procedure tcg64sparc.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1575. var
  1576. l : tlocation;
  1577. begin
  1578. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,l);
  1579. end;
  1580. procedure tcg64sparc.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1581. var
  1582. op1,op2:TAsmOp;
  1583. begin
  1584. case op of
  1585. OP_NEG,
  1586. OP_NOT :
  1587. internalerror(200306017);
  1588. end;
  1589. get_64bit_ops(op,op1,op2,setflags);
  1590. tcgsparc(cg).handle_reg_const_reg(list,op1,regsrc.reglo,tcgint(lo(value)),regdst.reglo);
  1591. tcgsparc(cg).handle_reg_const_reg(list,op2,regsrc.reghi,tcgint(hi(value)),regdst.reghi);
  1592. end;
  1593. procedure tcg64sparc.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1594. var
  1595. op1,op2:TAsmOp;
  1596. begin
  1597. case op of
  1598. OP_NEG,
  1599. OP_NOT :
  1600. internalerror(200306017);
  1601. end;
  1602. get_64bit_ops(op,op1,op2,setflags);
  1603. list.concat(taicpu.op_reg_reg_reg(op1,regsrc2.reglo,regsrc1.reglo,regdst.reglo));
  1604. list.concat(taicpu.op_reg_reg_reg(op2,regsrc2.reghi,regsrc1.reghi,regdst.reghi));
  1605. end;
  1606. procedure create_codegen;
  1607. begin
  1608. cg:=TCgSparc.Create;
  1609. if target_info.system=system_sparc_linux then
  1610. TCgSparc(cg).use_unlimited_pic_mode:=true
  1611. else
  1612. TCgSparc(cg).use_unlimited_pic_mode:=false;
  1613. cg64:=TCg64Sparc.Create;
  1614. end;
  1615. end.