cgcpu.pas 54 KB

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