cgcpu.pas 57 KB

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