cgcpu.pas 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the code generator for the SPARC
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cgbase,cgobj,cg64f32,
  23. aasmbase,aasmtai,aasmcpu,
  24. cpubase,cpuinfo,
  25. node,symconst,SymType,
  26. rgcpu;
  27. type
  28. TCgSparc=class(tcg)
  29. protected
  30. rgint,
  31. rgfpu : trgcpu;
  32. function IsSimpleRef(const ref:treference):boolean;
  33. public
  34. procedure init_register_allocators;override;
  35. procedure done_register_allocators;override;
  36. function getintregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  37. function getaddressregister(list:Taasmoutput):Tregister;override;
  38. function getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  39. function getmmregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  40. procedure getexplicitregister(list:Taasmoutput;r:Tregister);override;
  41. procedure ungetregister(list:Taasmoutput;r:Tregister);override;
  42. procedure add_move_instruction(instr:Taicpu);override;
  43. procedure do_register_allocation(list:Taasmoutput;headertai:tai);override;
  44. procedure allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  45. procedure deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  46. function uses_registers(rt:Tregistertype):boolean;override;
  47. { sparc special, needed by cg64 }
  48. procedure handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  49. procedure handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aword;dst:tregister);
  50. { parameter }
  51. procedure a_param_const(list:TAasmOutput;size:tcgsize;a:aword;const LocPara:TParaLocation);override;
  52. procedure a_param_ref(list:TAasmOutput;sz:tcgsize;const r:TReference;const LocPara:TParaLocation);override;
  53. procedure a_paramaddr_ref(list:TAasmOutput;const r:TReference;const LocPara:TParaLocation);override;
  54. procedure a_paramfpu_reg(list : taasmoutput;size : tcgsize;const r : tregister;const locpara : tparalocation);override;
  55. procedure a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const locpara : tparalocation);override;
  56. procedure a_loadany_param_ref(list : taasmoutput;const locpara : tparalocation;const ref:treference;shuffle : pmmshuffle);override;
  57. procedure a_loadany_param_reg(list : taasmoutput;const locpara : tparalocation;const reg:tregister;shuffle : pmmshuffle);override;
  58. procedure a_call_name(list:TAasmOutput;const s:string);override;
  59. procedure a_call_reg(list:TAasmOutput;Reg:TRegister);override;
  60. { General purpose instructions }
  61. procedure a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:AWord;reg:TRegister);override;
  62. procedure a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);override;
  63. procedure a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);override;
  64. procedure a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override;
  65. { move instructions }
  66. procedure a_load_const_reg(list:TAasmOutput;size:tcgsize;a:aword;reg:tregister);override;
  67. procedure a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;const ref:TReference);override;
  68. procedure a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCgSize;reg:TRegister;const ref:TReference);override;
  69. procedure a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);override;
  70. procedure a_load_reg_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;reg1,reg2:tregister);override;
  71. procedure a_loadaddr_ref_reg(list:TAasmOutput;const ref:TReference;r:tregister);override;
  72. { fpu move instructions }
  73. procedure a_loadfpu_reg_reg(list:TAasmOutput;size:tcgsize;reg1, reg2:tregister);override;
  74. procedure a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister);override;
  75. procedure a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);override;
  76. { comparison operations }
  77. procedure a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);override;
  78. procedure a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override;
  79. procedure a_jmp_always(List:TAasmOutput;l:TAsmLabel);override;
  80. procedure a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);{ override;}
  81. procedure a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel);override;
  82. procedure g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister);override;
  83. procedure g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef);override;
  84. procedure g_stackframe_entry(list:TAasmOutput;localsize:LongInt);override;
  85. procedure g_restore_all_registers(list:TAasmOutput;accused,acchiused:boolean);override;
  86. procedure g_restore_frame_pointer(list:TAasmOutput);override;
  87. procedure g_restore_standard_registers(list:taasmoutput);override;
  88. procedure g_return_from_proc(list:TAasmOutput;parasize:aword);override;
  89. procedure g_save_all_registers(list : taasmoutput);override;
  90. procedure g_save_standard_registers(list : taasmoutput);override;
  91. procedure g_concatcopy(list:TAasmOutput;const source,dest:TReference;len:aword;delsource,loadref:boolean);override;
  92. class function reg_cgsize(const reg:tregister):tcgsize;override;
  93. end;
  94. TCg64Sparc=class(tcg64f32)
  95. procedure a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);override;
  96. procedure a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);override;
  97. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  98. end;
  99. const
  100. TOpCG2AsmOp : array[topcg] of TAsmOp=(
  101. A_NONE,A_ADD,A_AND,A_UDIV,A_SDIV,A_UMUL,A_SMUL,A_NEG,A_NOT,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR
  102. );
  103. TOpCmp2AsmCond : array[topcmp] of TAsmCond=(
  104. C_NONE,C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A
  105. );
  106. implementation
  107. uses
  108. globtype,globals,verbose,systems,cutils,
  109. symdef,symsym,defutil,paramgr,
  110. tgobj,cpupi;
  111. {****************************************************************************
  112. This is private property, keep out! :)
  113. ****************************************************************************}
  114. function TCgSparc.IsSimpleRef(const ref:treference):boolean;
  115. begin
  116. if (ref.base=NR_NO) and (ref.index<>NR_NO) then
  117. InternalError(2002100804);
  118. result :=not(assigned(ref.symbol))and
  119. (((ref.index = NR_NO) and
  120. (ref.offset >= simm13lo) and
  121. (ref.offset <= simm13hi)) or
  122. ((ref.index <> NR_NO) and
  123. (ref.offset = 0)));
  124. end;
  125. procedure tcgsparc.handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
  126. var
  127. tmpreg : tregister;
  128. tmpref : treference;
  129. begin
  130. tmpreg:=NR_NO;
  131. { Be sure to have a base register }
  132. if (ref.base=NR_NO) then
  133. begin
  134. ref.base:=ref.index;
  135. ref.index:=NR_NO;
  136. end;
  137. { When need to use SETHI, do it first }
  138. if assigned(ref.symbol) or
  139. (ref.offset<simm13lo) or
  140. (ref.offset>simm13hi) then
  141. begin
  142. tmpreg:=GetIntRegister(list,OS_INT);
  143. reference_reset(tmpref);
  144. tmpref.symbol:=ref.symbol;
  145. tmpref.offset:=ref.offset;
  146. tmpref.symaddr:=refs_hi;
  147. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg));
  148. { Load the low part is left }
  149. {$warning TODO Maybe not needed to load symbol}
  150. tmpref.symaddr:=refs_lo;
  151. list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg));
  152. { The offset and symbol are loaded, reset in reference }
  153. ref.offset:=0;
  154. ref.symbol:=nil;
  155. { Only an index register or offset is allowed }
  156. if tmpreg<>NR_NO then
  157. begin
  158. if (ref.index<>NR_NO) then
  159. begin
  160. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
  161. ref.index:=tmpreg;
  162. end
  163. else
  164. begin
  165. if ref.base<>NR_NO then
  166. ref.index:=tmpreg
  167. else
  168. ref.base:=tmpreg;
  169. end;
  170. end;
  171. end;
  172. if (ref.base<>NR_NO) then
  173. begin
  174. if (ref.index<>NR_NO) and
  175. ((ref.offset<>0) or assigned(ref.symbol)) then
  176. begin
  177. if tmpreg=NR_NO then
  178. tmpreg:=GetIntRegister(list,OS_INT);
  179. if (ref.index<>NR_NO) then
  180. begin
  181. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
  182. ref.index:=NR_NO;
  183. end;
  184. end;
  185. end;
  186. if isstore then
  187. list.concat(taicpu.op_reg_ref(op,reg,ref))
  188. else
  189. list.concat(taicpu.op_ref_reg(op,ref,reg));
  190. if (tmpreg<>NR_NO) then
  191. UnGetRegister(list,tmpreg);
  192. end;
  193. procedure tcgsparc.handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aword;dst:tregister);
  194. var
  195. tmpreg : tregister;
  196. begin
  197. if (longint(a)<simm13lo) or
  198. (longint(a)>simm13hi) then
  199. begin
  200. tmpreg:=GetIntRegister(list,OS_INT);
  201. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,tmpreg));
  202. list.concat(taicpu.op_reg_const_reg(A_OR,tmpreg,a and aword($3ff),tmpreg));
  203. list.concat(taicpu.op_reg_reg_reg(op,src,tmpreg,dst));
  204. UnGetRegister(list,tmpreg);
  205. end
  206. else
  207. list.concat(taicpu.op_reg_const_reg(op,src,a,dst));
  208. end;
  209. {****************************************************************************
  210. Assembler code
  211. ****************************************************************************}
  212. procedure Tcgsparc.init_register_allocators;
  213. begin
  214. rgint:=Trgcpu.create(R_INTREGISTER,R_SUBWHOLE,
  215. [RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5,RS_O7,
  216. RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6,RS_L7],
  217. first_int_imreg,[]);
  218. rgfpu:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  219. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
  220. RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,
  221. RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,
  222. RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],
  223. first_fpu_imreg,[]);
  224. end;
  225. procedure Tcgsparc.done_register_allocators;
  226. begin
  227. rgint.free;
  228. rgfpu.free;
  229. end;
  230. function tcgsparc.getintregister(list:Taasmoutput;size:Tcgsize):Tregister;
  231. begin
  232. result:=rgint.getregister(list,R_SUBWHOLE);
  233. end;
  234. function tcgsparc.getaddressregister(list:Taasmoutput):Tregister;
  235. begin
  236. result:=rgint.getregister(list,R_SUBWHOLE);
  237. end;
  238. function tcgsparc.getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;
  239. begin
  240. if size=OS_F64 then
  241. result:=rgfpu.getregister(list,R_SUBFD)
  242. else
  243. result:=rgfpu.getregister(list,R_SUBWHOLE);
  244. end;
  245. function tcgsparc.getmmregister(list:Taasmoutput;size:Tcgsize):Tregister;
  246. begin
  247. internalerror(200310241);
  248. result:=RS_INVALID;
  249. end;
  250. procedure tcgsparc.getexplicitregister(list:Taasmoutput;r:Tregister);
  251. begin
  252. case getregtype(r) of
  253. R_INTREGISTER :
  254. rgint.getexplicitregister(list,r);
  255. R_FPUREGISTER :
  256. rgfpu.getexplicitregister(list,r);
  257. else
  258. internalerror(200310091);
  259. end;
  260. end;
  261. procedure tcgsparc.ungetregister(list:Taasmoutput;r:Tregister);
  262. begin
  263. case getregtype(r) of
  264. R_INTREGISTER :
  265. rgint.ungetregister(list,r);
  266. R_FPUREGISTER :
  267. rgfpu.ungetregister(list,r);
  268. else
  269. internalerror(200310091);
  270. end;
  271. end;
  272. procedure tcgsparc.allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  273. begin
  274. case rt of
  275. R_INTREGISTER :
  276. rgint.allocexplicitregisters(list,r);
  277. R_FPUREGISTER :
  278. rgfpu.allocexplicitregisters(list,r);
  279. R_MMREGISTER :;
  280. else
  281. internalerror(200310092);
  282. end;
  283. end;
  284. procedure tcgsparc.deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  285. begin
  286. case rt of
  287. R_INTREGISTER :
  288. rgint.deallocexplicitregisters(list,r);
  289. R_FPUREGISTER :
  290. rgfpu.deallocexplicitregisters(list,r);
  291. R_MMREGISTER :;
  292. else
  293. internalerror(200310093);
  294. end;
  295. end;
  296. function TCgSparc.uses_registers(rt:Tregistertype):boolean;
  297. begin
  298. case rt of
  299. R_INTREGISTER :
  300. result:=rgint.uses_registers;
  301. R_MMREGISTER :
  302. result:=false;
  303. R_FPUREGISTER :
  304. result:=rgfpu.uses_registers;
  305. else
  306. internalerror(2003120900);
  307. end;
  308. end;
  309. procedure tcgsparc.add_move_instruction(instr:Taicpu);
  310. begin
  311. rgint.add_move_instruction(instr);
  312. end;
  313. procedure tcgsparc.do_register_allocation(list:Taasmoutput;headertai:tai);
  314. begin
  315. { Int }
  316. rgint.do_register_allocation(list,headertai);
  317. rgint.translate_registers(list);
  318. { FPU }
  319. rgfpu.do_register_allocation(list,headertai);
  320. rgfpu.translate_registers(list);
  321. end;
  322. function TCgSparc.reg_cgsize(const reg:tregister):tcgsize;
  323. begin
  324. result:=OS_32;
  325. end;
  326. procedure TCgSparc.a_param_const(list:TAasmOutput;size:tcgsize;a:aword;const LocPara:TParaLocation);
  327. var
  328. Ref:TReference;
  329. begin
  330. case locpara.loc of
  331. LOC_REGISTER,LOC_CREGISTER:
  332. a_load_const_reg(list,size,a,locpara.register);
  333. LOC_REFERENCE:
  334. begin
  335. { Code conventions need the parameters being allocated in %o6+92 }
  336. if locpara.reference.offset<92 then
  337. InternalError(2002081104);
  338. reference_reset_base(ref,locpara.reference.index,locpara.reference.offset);
  339. a_load_const_ref(list,size,a,ref);
  340. end;
  341. else
  342. InternalError(2002122200);
  343. end;
  344. end;
  345. procedure TCgSparc.a_param_ref(list:TAasmOutput;sz:TCgSize;const r:TReference;const LocPara:TParaLocation);
  346. var
  347. ref: treference;
  348. tmpreg:TRegister;
  349. begin
  350. with LocPara do
  351. case loc of
  352. LOC_REGISTER,LOC_CREGISTER :
  353. a_load_ref_reg(list,sz,sz,r,Register);
  354. LOC_REFERENCE:
  355. begin
  356. { Code conventions need the parameters being allocated in %o6+92 }
  357. if locpara.reference.offset<92 then
  358. InternalError(2002081104);
  359. reference_reset_base(ref,locpara.reference.index,locpara.reference.offset);
  360. tmpreg:=GetIntRegister(list,OS_INT);
  361. a_load_ref_reg(list,sz,sz,r,tmpreg);
  362. a_load_reg_ref(list,sz,sz,tmpreg,ref);
  363. UnGetRegister(list,tmpreg);
  364. end;
  365. else
  366. internalerror(2002081103);
  367. end;
  368. end;
  369. procedure TCgSparc.a_paramaddr_ref(list:TAasmOutput;const r:TReference;const LocPara:TParaLocation);
  370. var
  371. Ref:TReference;
  372. TmpReg:TRegister;
  373. begin
  374. case locpara.loc of
  375. LOC_REGISTER,LOC_CREGISTER:
  376. a_loadaddr_ref_reg(list,r,locpara.register);
  377. LOC_REFERENCE:
  378. begin
  379. reference_reset(ref);
  380. ref.base := locpara.reference.index;
  381. ref.offset := locpara.reference.offset;
  382. tmpreg:=GetAddressRegister(list);
  383. a_loadaddr_ref_reg(list,r,tmpreg);
  384. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  385. UnGetRegister(list,tmpreg);
  386. end;
  387. else
  388. internalerror(2002080701);
  389. end;
  390. end;
  391. procedure tcgsparc.a_paramfpu_reg(list : taasmoutput;size : tcgsize;const r : tregister;const locpara : tparalocation);
  392. var
  393. href : treference;
  394. begin
  395. tg.GetTemp(list,TCGSize2Size[size],tt_normal,href);
  396. a_loadfpu_reg_ref(list,size,r,href);
  397. a_paramfpu_ref(list,size,href,locpara);
  398. tg.Ungettemp(list,href);
  399. end;
  400. procedure tcgsparc.a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const locpara : tparalocation);
  401. var
  402. templocpara : tparalocation;
  403. begin
  404. { floats are pushed in the int registers }
  405. templocpara:=locpara;
  406. case locpara.size of
  407. OS_F32 :
  408. begin
  409. templocpara.size:=OS_32;
  410. a_param_ref(list,OS_32,ref,templocpara);
  411. end;
  412. OS_F64 :
  413. begin
  414. templocpara.size:=OS_64;
  415. cg64.a_param64_ref(list,ref,templocpara);
  416. end;
  417. else
  418. internalerror(200307021);
  419. end;
  420. end;
  421. procedure tcgsparc.a_loadany_param_ref(list : taasmoutput;const locpara : tparalocation;const ref:treference;shuffle : pmmshuffle);
  422. var
  423. href,
  424. tempref : treference;
  425. templocpara : tparalocation;
  426. begin
  427. { Load floats like ints }
  428. templocpara:=locpara;
  429. case locpara.size of
  430. OS_F32 :
  431. templocpara.size:=OS_32;
  432. OS_F64 :
  433. templocpara.size:=OS_64;
  434. end;
  435. { Word 0 is in register, word 1 is in reference }
  436. if (templocpara.loc=LOC_REFERENCE) and (templocpara.low_in_reg) then
  437. begin
  438. tempref:=ref;
  439. cg.a_load_reg_ref(list,OS_INT,OS_INT,templocpara.register,tempref);
  440. inc(tempref.offset,4);
  441. reference_reset_base(href,templocpara.reference.index,templocpara.reference.offset);
  442. cg.a_load_ref_ref(list,OS_INT,OS_INT,href,tempref);
  443. end
  444. else
  445. inherited a_loadany_param_ref(list,templocpara,ref,shuffle);
  446. end;
  447. procedure tcgsparc.a_loadany_param_reg(list : taasmoutput;const locpara : tparalocation;const reg:tregister;shuffle : pmmshuffle);
  448. var
  449. href : treference;
  450. begin
  451. { Word 0 is in register, word 1 is in reference, not
  452. possible to load it in 1 register }
  453. if (locpara.loc=LOC_REFERENCE) and (locpara.low_in_reg) then
  454. internalerror(200307011);
  455. { Float load use a temp reference }
  456. if locpara.size in [OS_F32,OS_F64] then
  457. begin
  458. tg.GetTemp(list,TCGSize2Size[locpara.size],tt_normal,href);
  459. a_loadany_param_ref(list,locpara,href,shuffle);
  460. a_loadfpu_ref_reg(list,locpara.size,href,reg);
  461. tg.Ungettemp(list,href);
  462. end
  463. else
  464. inherited a_loadany_param_reg(list,locpara,reg,shuffle);
  465. end;
  466. procedure TCgSparc.a_call_name(list:TAasmOutput;const s:string);
  467. begin
  468. list.concat(taicpu.op_sym(A_CALL,objectlibrary.newasmsymbol(s)));
  469. { Delay slot }
  470. list.concat(taicpu.op_none(A_NOP));
  471. end;
  472. procedure TCgSparc.a_call_reg(list:TAasmOutput;Reg:TRegister);
  473. begin
  474. list.concat(taicpu.op_reg(A_CALL,reg));
  475. { Delay slot }
  476. list.concat(taicpu.op_none(A_NOP));
  477. end;
  478. {********************** load instructions ********************}
  479. procedure TCgSparc.a_load_const_reg(list : TAasmOutput;size : TCGSize;a : aword;reg : TRegister);
  480. begin
  481. { we don't use the set instruction here because it could be evalutated to two
  482. instructions which would cause problems with the delay slot (FK) }
  483. { sethi allows to set the upper 22 bit, so we'll take full advantage of it }
  484. if (a and aword($1fff))=0 then
  485. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg))
  486. else if (longint(a)>=simm13lo) and (longint(a)<=simm13hi) then
  487. list.concat(taicpu.op_reg_const_reg(A_OR,NR_G0,a,reg))
  488. else
  489. begin
  490. list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg));
  491. list.concat(taicpu.op_reg_const_reg(A_OR,reg,a and aword($3ff),reg));
  492. end;
  493. end;
  494. procedure TCgSparc.a_load_const_ref(list : TAasmOutput;size : tcgsize;a : aword;const ref : TReference);
  495. begin
  496. if a=0 then
  497. a_load_reg_ref(list,size,size,NR_G0,ref)
  498. else
  499. inherited a_load_const_ref(list,size,a,ref);
  500. end;
  501. procedure TCgSparc.a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCGSize;reg:tregister;const Ref:TReference);
  502. var
  503. op:tasmop;
  504. begin
  505. case ToSize of
  506. { signed integer registers }
  507. OS_8,
  508. OS_S8:
  509. Op:=A_STB;
  510. OS_16,
  511. OS_S16:
  512. Op:=A_STH;
  513. OS_32,
  514. OS_S32:
  515. Op:=A_ST;
  516. else
  517. InternalError(2002122100);
  518. end;
  519. handle_load_store(list,true,op,reg,ref);
  520. end;
  521. procedure TCgSparc.a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);
  522. var
  523. op:tasmop;
  524. begin
  525. case Fromsize of
  526. { signed integer registers }
  527. OS_S8:
  528. Op:=A_LDSB;{Load Signed Byte}
  529. OS_8:
  530. Op:=A_LDUB;{Load Unsigned Bye}
  531. OS_S16:
  532. Op:=A_LDSH;{Load Signed Halfword}
  533. OS_16:
  534. Op:=A_LDUH;{Load Unsigned Halfword}
  535. OS_S32,
  536. OS_32:
  537. Op:=A_LD;{Load Word}
  538. else
  539. InternalError(2002122101);
  540. end;
  541. handle_load_store(list,false,op,reg,ref);
  542. end;
  543. procedure TCgSparc.a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);
  544. begin
  545. if (reg1<>reg2) or
  546. (tcgsize2size[tosize]<tcgsize2size[fromsize]) or
  547. (
  548. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  549. (tosize <> fromsize) and
  550. not(fromsize in [OS_32,OS_S32])
  551. ) then
  552. begin
  553. {$warning TODO Sign extension}
  554. case tosize of
  555. OS_8,OS_S8:
  556. a_op_const_reg_reg(list,OP_AND,tosize,$ff,reg1,reg2);
  557. OS_16,OS_S16:
  558. a_op_const_reg_reg(list,OP_AND,tosize,$ffff,reg1,reg2);
  559. OS_32,OS_S32:
  560. begin
  561. if reg1<>reg2 then
  562. list.Concat(taicpu.op_reg_reg(A_MOV,reg1,reg2));
  563. end;
  564. else
  565. internalerror(2002090901);
  566. end;
  567. end;
  568. end;
  569. procedure TCgSparc.a_loadaddr_ref_reg(list : TAasmOutput;const ref : TReference;r : tregister);
  570. var
  571. tmpref : treference;
  572. hreg : tregister;
  573. begin
  574. if (ref.base=NR_NO) and (ref.index<>NR_NO) then
  575. internalerror(200306171);
  576. { At least big offset (need SETHI), maybe base and maybe index }
  577. if assigned(ref.symbol) or
  578. (ref.offset<simm13lo) or
  579. (ref.offset>simm13hi) then
  580. begin
  581. if (ref.base<>r) and (ref.index<>r) then
  582. hreg:=r
  583. else
  584. hreg:=GetAddressRegister(list);
  585. reference_reset(tmpref);
  586. tmpref.symbol := ref.symbol;
  587. tmpref.offset := ref.offset;
  588. tmpref.symaddr := refs_hi;
  589. list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg));
  590. { Only the low part is left }
  591. tmpref.symaddr:=refs_lo;
  592. list.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg));
  593. if ref.base<>NR_NO then
  594. begin
  595. if ref.index<>NR_NO then
  596. begin
  597. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.base,hreg));
  598. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.index,r));
  599. end
  600. else
  601. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.base,r));
  602. end
  603. else
  604. begin
  605. if hreg<>r then
  606. list.Concat(taicpu.op_reg_reg(A_MOV,hreg,r));
  607. end;
  608. if hreg<>r then
  609. UnGetRegister(list,hreg);
  610. end
  611. else
  612. { At least small offset, maybe base and maybe index }
  613. if ref.offset<>0 then
  614. begin
  615. if ref.base<>NR_NO then
  616. begin
  617. if ref.index<>NR_NO then
  618. begin
  619. if (ref.base<>r) and (ref.index<>r) then
  620. hreg:=r
  621. else
  622. hreg:=GetAddressRegister(list);
  623. list.concat(taicpu.op_reg_const_reg(A_ADD,ref.base,aword(ref.offset),hreg));
  624. list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,ref.index,r));
  625. if hreg<>r then
  626. UnGetRegister(list,hreg);
  627. end
  628. else
  629. list.concat(taicpu.op_reg_const_reg(A_ADD,ref.base,aword(ref.offset),r));
  630. end
  631. else
  632. list.concat(taicpu.op_reg_const_reg(A_ADD,NR_G0,aword(ref.offset),r));
  633. end
  634. else
  635. { Both base and index }
  636. if ref.index<>NR_NO then
  637. list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,r))
  638. else
  639. { Only base }
  640. if ref.base<>NR_NO then
  641. a_load_reg_reg(list,OS_INT,OS_INT,ref.base,r)
  642. else
  643. internalerror(200306172);
  644. end;
  645. procedure TCgSparc.a_loadfpu_reg_reg(list:TAasmOutput;size:tcgsize;reg1, reg2:tregister);
  646. begin
  647. if reg1<>reg2 then
  648. begin
  649. list.concat(taicpu.op_reg_reg(A_FMOVs,reg1,reg2));
  650. if size=OS_F64 then
  651. begin
  652. setsupreg(reg1,getsupreg(reg1)+1);
  653. setsupreg(reg2,getsupreg(reg2)+1);
  654. list.concat(taicpu.op_reg_reg(A_FMOVs,reg1,reg2));
  655. end;
  656. end;
  657. end;
  658. procedure TCgSparc.a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister);
  659. const
  660. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  661. (A_LDF,A_LDDF);
  662. begin
  663. { several functions call this procedure with OS_32 or OS_64 }
  664. { so this makes life easier (FK) }
  665. case size of
  666. OS_32,OS_F32:
  667. size:=OS_F32;
  668. OS_64,OS_F64,OS_C64:
  669. size:=OS_F64;
  670. else
  671. internalerror(200201121);
  672. end;
  673. handle_load_store(list,false,fpuloadinstr[size],reg,ref);
  674. end;
  675. procedure TCgSparc.a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);
  676. const
  677. FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp =
  678. (A_STF,A_STDF);
  679. begin
  680. { several functions call this procedure with OS_32 or OS_64 }
  681. { so this makes life easier (FK) }
  682. case size of
  683. OS_32,OS_F32:
  684. size:=OS_F32;
  685. OS_64,OS_F64,OS_C64:
  686. size:=OS_F64;
  687. else
  688. internalerror(200201121);
  689. end;
  690. handle_load_store(list,true,fpuloadinstr[size],reg,ref);
  691. end;
  692. procedure TCgSparc.a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:AWord;reg:TRegister);
  693. begin
  694. if Op in [OP_NEG,OP_NOT] then
  695. internalerror(200306011);
  696. if (a=0) then
  697. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],reg,NR_G0,reg))
  698. else
  699. handle_reg_const_reg(list,TOpCG2AsmOp[op],reg,a,reg);
  700. end;
  701. procedure TCgSparc.a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);
  702. begin
  703. Case Op of
  704. OP_NEG,
  705. OP_NOT:
  706. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],src,dst));
  707. else
  708. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src,dst));
  709. end;
  710. end;
  711. procedure TCgSparc.a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);
  712. var
  713. power : longInt;
  714. begin
  715. case op of
  716. OP_IMUL :
  717. begin
  718. if not(cs_check_overflow in aktlocalswitches) and
  719. ispowerof2(a,power) then
  720. begin
  721. { can be done with a shift }
  722. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  723. exit;
  724. end;
  725. end;
  726. OP_SUB,
  727. OP_ADD :
  728. begin
  729. if (a=0) then
  730. begin
  731. a_load_reg_reg(list,size,size,src,dst);
  732. exit;
  733. end;
  734. end;
  735. end;
  736. handle_reg_const_reg(list,TOpCG2AsmOp[op],src,a,dst);
  737. end;
  738. procedure TCgSparc.a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);
  739. begin
  740. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst));
  741. end;
  742. {*************** compare instructructions ****************}
  743. procedure TCgSparc.a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);
  744. begin
  745. if (a=0) then
  746. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg,NR_G0,NR_G0))
  747. else
  748. handle_reg_const_reg(list,A_SUBcc,reg,a,NR_G0);
  749. a_jmp_cond(list,cmp_op,l);
  750. end;
  751. procedure TCgSparc.a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);
  752. begin
  753. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg2,reg1,NR_G0));
  754. a_jmp_cond(list,cmp_op,l);
  755. end;
  756. procedure TCgSparc.a_jmp_always(List:TAasmOutput;l:TAsmLabel);
  757. begin
  758. List.Concat(TAiCpu.op_sym(A_BA,objectlibrary.newasmsymbol(l.name)));
  759. { Delay slot }
  760. list.Concat(TAiCpu.Op_none(A_NOP));
  761. end;
  762. procedure TCgSparc.a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:TAsmLabel);
  763. var
  764. ai:TAiCpu;
  765. begin
  766. ai:=TAiCpu.Op_sym(A_Bxx,l);
  767. ai.SetCondition(TOpCmp2AsmCond[cond]);
  768. list.Concat(ai);
  769. { Delay slot }
  770. list.Concat(TAiCpu.Op_none(A_NOP));
  771. end;
  772. procedure TCgSparc.a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel);
  773. var
  774. ai:taicpu;
  775. begin
  776. ai := Taicpu.op_sym(A_Bxx,l);
  777. ai.SetCondition(flags_to_cond(f));
  778. list.Concat(ai);
  779. { Delay slot }
  780. list.Concat(TAiCpu.Op_none(A_NOP));
  781. end;
  782. procedure TCgSparc.g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister);
  783. var
  784. hl : tasmlabel;
  785. begin
  786. objectlibrary.getlabel(hl);
  787. a_load_const_reg(list,size,1,reg);
  788. a_jmp_flags(list,f,hl);
  789. a_load_const_reg(list,size,0,reg);
  790. a_label(list,hl);
  791. end;
  792. procedure TCgSparc.g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef);
  793. var
  794. hl : tasmlabel;
  795. begin
  796. if not(cs_check_overflow in aktlocalswitches) then
  797. exit;
  798. objectlibrary.getlabel(hl);
  799. if not((def.deftype=pointerdef)or
  800. ((def.deftype=orddef)and
  801. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  802. begin
  803. //r.enum:=R_CR7;
  804. //list.concat(taicpu.op_reg(A_MCRXR,r));
  805. //a_jmp_cond(list,A_Bxx,C_OV,hl)
  806. a_jmp_always(list,hl)
  807. end
  808. else
  809. a_jmp_cond(list,OC_AE,hl);
  810. a_call_name(list,'FPC_OVERFLOW');
  811. a_label(list,hl);
  812. end;
  813. { *********** entry/exit code and address loading ************ }
  814. procedure TCgSparc.g_stackframe_entry(list:TAasmOutput;LocalSize:LongInt);
  815. begin
  816. { Althogh the SPARC architecture require only word alignment, software
  817. convention and the operating system require every stack frame to be double word
  818. aligned }
  819. LocalSize:=align(LocalSize,8);
  820. { Execute the SAVE instruction to get a new register window and create a new
  821. stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state
  822. before execution of the SAVE instrucion so it is the caller %i6, when the %i6
  823. after execution of that instruction is the called function stack pointer}
  824. list.concat(Taicpu.Op_reg_const_reg(A_SAVE,NR_STACK_POINTER_REG,aword(-LocalSize),NR_STACK_POINTER_REG));
  825. end;
  826. procedure TCgSparc.g_restore_all_registers(list:TaasmOutput;accused,acchiused:boolean);
  827. begin
  828. { The sparc port uses the sparc standard calling convetions so this function has no used }
  829. end;
  830. procedure TCgSparc.g_restore_frame_pointer(list:TAasmOutput);
  831. begin
  832. { This function intontionally does nothing as frame pointer is restored in the
  833. delay slot of the return instrucion done in g_return_from_proc}
  834. end;
  835. procedure TCgSparc.g_restore_standard_registers(list:taasmoutput);
  836. begin
  837. { The sparc port uses the sparc standard calling convetions so this function has no used }
  838. end;
  839. procedure TCgSparc.g_return_from_proc(list:TAasmOutput;parasize:aword);
  840. begin
  841. { According to the SPARC ABI, the stack is cleared using the RESTORE instruction
  842. which is genereted in the g_restore_frame_pointer. Notice that SPARC has no
  843. real RETURN instruction and that JMPL is used instead. The JMPL instrucion have one
  844. delay slot, so an inversion is possible such as
  845. RET (=JMPL %i7+8,%g0)
  846. RESTORE (=RESTORE %g0,0,%g0)
  847. If no inversion we can use just
  848. RESTORE (=RESTORE %g0,0,%g0)
  849. RET (=JMPL %i7+8,%g0)
  850. NOP
  851. }
  852. list.concat(Taicpu.op_none(A_RET));
  853. { We use trivial restore in the delay slot of the JMPL instruction, as we
  854. already set result onto %i0 }
  855. list.concat(Taicpu.op_none(A_RESTORE));
  856. end;
  857. procedure TCgSparc.g_save_all_registers(list : taasmoutput);
  858. begin
  859. { The sparc port uses the sparc standard calling convetions so this function has no used }
  860. end;
  861. procedure TCgSparc.g_save_standard_registers(list : taasmoutput);
  862. begin
  863. { The sparc port uses the sparc standard calling convetions so this function has no used }
  864. end;
  865. { ************* concatcopy ************ }
  866. procedure TCgSparc.g_concatcopy(list:taasmoutput;const source,dest:treference;len:aword;delsource,loadref:boolean);
  867. var
  868. hreg,
  869. countreg: TRegister;
  870. src, dst: TReference;
  871. lab: tasmlabel;
  872. count, count2: aword;
  873. orgsrc, orgdst: boolean;
  874. begin
  875. if len > high(longint) then
  876. internalerror(2002072704);
  877. { make sure short loads are handled as optimally as possible }
  878. if not loadref then
  879. begin
  880. if (len <= 8) and (byte(len) in [1,2,4,8]) then
  881. begin
  882. if len < 8 then
  883. begin
  884. a_load_ref_ref(list,int_cgsize(len),int_cgsize(len),source,dest);
  885. if delsource then
  886. reference_release(list,source);
  887. end
  888. else
  889. begin
  890. a_reg_alloc(list,NR_F0);
  891. a_loadfpu_ref_reg(list,OS_F64,source,NR_F0);
  892. if delsource then
  893. reference_release(list,source);
  894. a_loadfpu_reg_ref(list,OS_F64,NR_F0,dest);
  895. a_reg_dealloc(list,NR_F0);
  896. end;
  897. exit;
  898. end;
  899. end;
  900. reference_reset(src);
  901. reference_reset(dst);
  902. { load the address of source into src.base }
  903. if loadref then
  904. begin
  905. src.base:=GetAddressRegister(list);
  906. a_load_ref_reg(list,OS_32,OS_32,source,src.base);
  907. orgsrc := false;
  908. end
  909. else
  910. if not issimpleref(source) or
  911. (
  912. (source.index<>NR_NO) and
  913. (((source.offset+longint(len))>simm13hi) or
  914. ((source.offset+longint(len))<simm13lo))
  915. ) then
  916. begin
  917. src.base:=GetAddressRegister(list);
  918. a_loadaddr_ref_reg(list,source,src.base);
  919. orgsrc := false;
  920. end
  921. else
  922. begin
  923. src := source;
  924. orgsrc := true;
  925. end;
  926. if not orgsrc and delsource then
  927. reference_release(list,source);
  928. { load the address of dest into dst.base }
  929. if not issimpleref(dest) or
  930. (
  931. (dest.index<>NR_NO) and
  932. (((dest.offset + longint(len)) > simm13hi) or
  933. ((dest.offset + longint(len)) < simm13lo))
  934. ) then
  935. begin
  936. dst.base:=GetAddressRegister(list);
  937. a_loadaddr_ref_reg(list,dest,dst.base);
  938. orgdst := false;
  939. end
  940. else
  941. begin
  942. dst := dest;
  943. orgdst := true;
  944. end;
  945. { generate a loop }
  946. count:=len div 8;
  947. if count>4 then
  948. begin
  949. { the offsets are zero after the a_loadaddress_ref_reg and just }
  950. { have to be set to 8. I put an Inc there so debugging may be }
  951. { easier (should offset be different from zero here, it will be }
  952. { easy to notice in the generated assembler }
  953. inc(dst.offset,8);
  954. inc(src.offset,8);
  955. list.concat(taicpu.op_reg_const_reg(A_SUB,src.base,8,src.base));
  956. list.concat(taicpu.op_reg_const_reg(A_SUB,dst.base,8,dst.base));
  957. countreg:=GetIntRegister(list,OS_INT);
  958. a_load_const_reg(list,OS_INT,count,countreg);
  959. { explicitely allocate R_O0 since it can be used safely here }
  960. { (for holding date that's being copied) }
  961. a_reg_alloc(list,NR_F0);
  962. objectlibrary.getlabel(lab);
  963. a_label(list, lab);
  964. list.concat(taicpu.op_reg_const_reg(A_SUB,countreg,1,countreg));
  965. list.concat(taicpu.op_ref_reg(A_LDF,src,NR_F0));
  966. list.concat(taicpu.op_reg_ref(A_STD,NR_F0,dst));
  967. //a_jmp(list,A_BC,C_NE,0,lab);
  968. UnGetRegister(list,countreg);
  969. a_reg_dealloc(list,NR_F0);
  970. len := len mod 8;
  971. end;
  972. { unrolled loop }
  973. count:=len and 7;
  974. if count>0 then
  975. begin
  976. a_reg_alloc(list,NR_F0);
  977. for count2 := 1 to count do
  978. begin
  979. a_loadfpu_ref_reg(list,OS_F64,src,NR_F0);
  980. a_loadfpu_reg_ref(list,OS_F64,NR_F0,dst);
  981. inc(src.offset,8);
  982. inc(dst.offset,8);
  983. end;
  984. a_reg_dealloc(list,NR_F0);
  985. len := len mod 8;
  986. end;
  987. if (len and 4) <> 0 then
  988. begin
  989. hreg:=GetIntRegister(list,OS_INT);
  990. a_load_ref_reg(list,OS_32,OS_32,src,hreg);
  991. a_load_reg_ref(list,OS_32,OS_32,hreg,dst);
  992. inc(src.offset,4);
  993. inc(dst.offset,4);
  994. UnGetRegister(list,hreg);
  995. end;
  996. { copy the leftovers }
  997. if (len and 2) <> 0 then
  998. begin
  999. hreg:=GetIntRegister(list,OS_INT);
  1000. a_load_ref_reg(list,OS_16,OS_16,src,hreg);
  1001. a_load_reg_ref(list,OS_16,OS_16,hreg,dst);
  1002. inc(src.offset,2);
  1003. inc(dst.offset,2);
  1004. UnGetRegister(list,hreg);
  1005. end;
  1006. if (len and 1) <> 0 then
  1007. begin
  1008. hreg:=GetIntRegister(list,OS_INT);
  1009. a_load_ref_reg(list,OS_8,OS_8,src,hreg);
  1010. a_load_reg_ref(list,OS_8,OS_8,hreg,dst);
  1011. UnGetRegister(list,hreg);
  1012. end;
  1013. if orgsrc then
  1014. begin
  1015. if delsource then
  1016. reference_release(list,source);
  1017. end
  1018. else
  1019. UnGetRegister(list,src.base);
  1020. if not orgdst then
  1021. UnGetRegister(list,dst.base);
  1022. end;
  1023. {****************************************************************************
  1024. TCG64Sparc
  1025. ****************************************************************************}
  1026. procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  1027. begin
  1028. case op of
  1029. OP_ADD :
  1030. begin
  1031. op1:=A_ADD;
  1032. op2:=A_ADDX;
  1033. end;
  1034. OP_SUB :
  1035. begin
  1036. op1:=A_SUB;
  1037. op2:=A_SUBX;
  1038. end;
  1039. OP_XOR :
  1040. begin
  1041. op1:=A_XOR;
  1042. op2:=A_XOR;
  1043. end;
  1044. OP_OR :
  1045. begin
  1046. op1:=A_OR;
  1047. op2:=A_OR;
  1048. end;
  1049. OP_AND :
  1050. begin
  1051. op1:=A_AND;
  1052. op2:=A_AND;
  1053. end;
  1054. else
  1055. internalerror(200203241);
  1056. end;
  1057. end;
  1058. procedure TCg64Sparc.a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);
  1059. var
  1060. op1,op2 : TAsmOp;
  1061. begin
  1062. case op of
  1063. OP_NEG :
  1064. begin
  1065. list.concat(taicpu.op_reg_reg_reg(A_XNOR,NR_G0,regsrc.reghi,regdst.reghi));
  1066. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,NR_G0,regsrc.reglo,regdst.reglo));
  1067. list.concat(taicpu.op_reg_const_reg(A_ADDX,regdst.reglo,aword(-1),regdst.reglo));
  1068. exit;
  1069. end;
  1070. OP_NOT :
  1071. begin
  1072. list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reglo,NR_G0,regdst.reglo));
  1073. list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reghi,NR_G0,regdst.reghi));
  1074. exit;
  1075. end;
  1076. end;
  1077. get_64bit_ops(op,op1,op2);
  1078. list.concat(taicpu.op_reg_reg_reg(op1,regdst.reglo,regsrc.reglo,regdst.reglo));
  1079. list.concat(taicpu.op_reg_reg_reg(op2,regdst.reghi,regsrc.reghi,regdst.reghi));
  1080. end;
  1081. procedure TCg64Sparc.a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);
  1082. var
  1083. op1,op2:TAsmOp;
  1084. begin
  1085. case op of
  1086. OP_NEG,
  1087. OP_NOT :
  1088. internalerror(200306017);
  1089. end;
  1090. get_64bit_ops(op,op1,op2);
  1091. tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reglo,lo(value),regdst.reglo);
  1092. tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reghi,hi(value),regdst.reghi);
  1093. end;
  1094. begin
  1095. cg:=TCgSparc.Create;
  1096. cg64:=TCg64Sparc.Create;
  1097. end.
  1098. {
  1099. $Log$
  1100. Revision 1.73 2003-12-09 09:44:22 mazen
  1101. + added uses_registers overloaded method for sparc
  1102. Revision 1.72 2003/10/29 15:18:33 mazen
  1103. + added fake MM Registers support because of generic code need it.
  1104. Revision 1.71 2003/10/24 15:20:37 peter
  1105. * added more register functions
  1106. Revision 1.70 2003/10/24 11:14:46 mazen
  1107. * rg.[un]GetRegister* ==> [Un]Get[*]Register
  1108. Revision 1.69 2003/10/01 20:34:49 peter
  1109. * procinfo unit contains tprocinfo
  1110. * cginfo renamed to cgbase
  1111. * moved cgmessage to verbose
  1112. * fixed ppc and sparc compiles
  1113. Revision 1.68 2003/09/14 21:35:52 peter
  1114. * flags2reg fixed
  1115. * fixed 64bit not
  1116. Revision 1.67 2003/09/14 19:19:04 peter
  1117. * updates for new ra
  1118. Revision 1.66 2003/09/03 15:55:01 peter
  1119. * NEWRA branch merged
  1120. Revision 1.65.2.1 2003/09/01 21:02:55 peter
  1121. * sparc updates for new tregister
  1122. Revision 1.65 2003/07/08 21:24:59 peter
  1123. * sparc fixes
  1124. Revision 1.64 2003/07/06 22:10:13 peter
  1125. * operand order of cmp fixed
  1126. Revision 1.63 2003/07/06 17:58:22 peter
  1127. * framepointer fixes for sparc
  1128. * parent framepointer code more generic
  1129. Revision 1.62 2003/07/03 21:09:53 peter
  1130. * delay slot NOPs and comments added
  1131. * a_loadaddr_ref_reg fixed and optimized to reuse passed register
  1132. if it is not used by the ref
  1133. Revision 1.61 2003/07/02 22:18:04 peter
  1134. * paraloc splitted in callerparaloc,calleeparaloc
  1135. * sparc calling convention updates
  1136. Revision 1.60 2003/06/17 16:35:56 peter
  1137. * a_loadaddr_ref_reg fixed
  1138. Revision 1.59 2003/06/13 21:19:32 peter
  1139. * current_procdef removed, use current_procinfo.procdef instead
  1140. Revision 1.58 2003/06/12 16:43:07 peter
  1141. * newra compiles for sparc
  1142. Revision 1.57 2003/06/04 20:59:37 mazen
  1143. + added size of destination in code gen methods
  1144. + making g_overflowcheck declaration same as
  1145. ancestor's method declaration
  1146. Revision 1.56 2003/06/01 21:38:06 peter
  1147. * getregisterfpu size parameter added
  1148. * op_const_reg size parameter added
  1149. * sparc updates
  1150. Revision 1.55 2003/06/01 01:04:35 peter
  1151. * reference fixes
  1152. Revision 1.54 2003/05/31 01:00:51 peter
  1153. * register fixes
  1154. Revision 1.53 2003/05/30 23:57:08 peter
  1155. * more sparc cleanup
  1156. * accumulator removed, splitted in function_return_reg (called) and
  1157. function_result_reg (caller)
  1158. Revision 1.52 2003/05/28 23:18:31 florian
  1159. * started to fix and clean up the sparc port
  1160. Revision 1.51 2003/05/26 22:04:57 mazen
  1161. * added 64 bit value support to fix a problem in RTL
  1162. Revision 1.50 2003/05/23 22:33:48 florian
  1163. * fix some small flaws which prevent sparc linux system unit from compiling
  1164. * some reformatting done
  1165. Revision 1.49 2003/05/22 16:11:22 florian
  1166. * fixed sparc compilation partially
  1167. Revision 1.48 2003/05/07 15:04:30 mazen
  1168. * invalid genrated code for CASE statement fixed
  1169. Revision 1.47 2003/05/06 20:25:20 mazen
  1170. * Invalid genrated code : A_JMPL changed to A_BA
  1171. Revision 1.46 2003/05/06 15:02:40 mazen
  1172. * fixed a bug in a_load_const_reg related to max 13bit value limit
  1173. for immediat value ==> use of A_SETHI for greater values
  1174. Revision 1.45 2003/04/29 11:58:21 mazen
  1175. * fixed bug of output generated assembler for a_cmp_const_ref_label
  1176. Revision 1.44 2003/04/28 09:44:42 mazen
  1177. + NOP after conditional jump instruction to prevent delay slot execution
  1178. Revision 1.43 2003/04/27 11:21:36 peter
  1179. * aktprocdef renamed to current_procinfo.procdef
  1180. * procinfo renamed to current_procinfo
  1181. * procinfo will now be stored in current_module so it can be
  1182. cleaned up properly
  1183. * gen_main_procsym changed to create_main_proc and release_main_proc
  1184. to also generate a tprocinfo structure
  1185. * fixed unit implicit initfinal
  1186. Revision 1.42 2003/03/16 20:45:45 mazen
  1187. * fixing an LD operation without refernce in loading address parameters
  1188. Revision 1.41 2003/03/10 21:59:54 mazen
  1189. * fixing index overflow in handling new registers arrays.
  1190. Revision 1.40 2003/02/25 21:41:44 mazen
  1191. * code re-aligned 2 spaces
  1192. Revision 1.39 2003/02/19 22:00:16 daniel
  1193. * Code generator converted to new register notation
  1194. - Horribily outdated todo.txt removed
  1195. Revision 1.38 2003/02/18 22:00:20 mazen
  1196. * asm condition generation modified by TAiCpu.SetCondition
  1197. Revision 1.37 2003/02/05 21:48:34 mazen
  1198. * fixing run time errors related to unimplemented abstract methods in CG
  1199. + giving empty emplementations for some RTL functions
  1200. Revision 1.36 2003/01/22 22:30:03 mazen
  1201. - internal errors rmoved from a_loar_reg_reg when reg sizes differs from 32
  1202. Revision 1.35 2003/01/20 22:21:36 mazen
  1203. * many stuff related to RTL fixed
  1204. Revision 1.34 2003/01/08 18:43:58 daniel
  1205. * Tregister changed into a record
  1206. Revision 1.33 2003/01/07 22:03:40 mazen
  1207. * adding unequaln node support to sparc compiler
  1208. Revision 1.32 2003/01/06 22:51:47 mazen
  1209. * fixing bugs related to load_reg_ref
  1210. Revision 1.31 2003/01/05 21:32:35 mazen
  1211. * fixing several bugs compiling the RTL
  1212. Revision 1.30 2003/01/05 13:36:53 florian
  1213. * x86-64 compiles
  1214. + very basic support for float128 type (x86-64 only)
  1215. Revision 1.29 2002/12/25 20:59:49 mazen
  1216. - many emitXXX removed from cga.pas in order to remove that file.
  1217. Revision 1.28 2002/12/22 19:26:31 mazen
  1218. * many internal errors related to unimplemented nodes are fixed
  1219. Revision 1.27 2002/12/21 23:21:47 mazen
  1220. + added support for the shift nodes
  1221. + added debug output on screen with -an command line option
  1222. Revision 1.26 2002/11/25 19:21:49 mazen
  1223. * fixed support of nSparcInline
  1224. Revision 1.25 2002/11/25 17:43:28 peter
  1225. * splitted defbase in defutil,symutil,defcmp
  1226. * merged isconvertable and is_equal into compare_defs(_ext)
  1227. * made operator search faster by walking the list only once
  1228. Revision 1.24 2002/11/17 17:49:09 mazen
  1229. + return_result_reg and FUNCTION_RESULT_REG are now used, in all plateforms, to pass functions result between called function and its caller. See the explanation of each one
  1230. Revision 1.23 2002/11/10 19:07:46 mazen
  1231. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  1232. Revision 1.22 2002/11/06 11:31:24 mazen
  1233. * op_reg_reg_reg don't need any more a TOpSize parameter
  1234. Revision 1.21 2002/11/05 16:15:00 mazen
  1235. *** empty log message ***
  1236. Revision 1.20 2002/11/03 20:22:40 mazen
  1237. * parameter handling updated
  1238. Revision 1.19 2002/10/28 20:59:17 mazen
  1239. * TOpSize values changed S_L --> S_SW
  1240. Revision 1.18 2002/10/22 13:43:01 mazen
  1241. - cga.pas redueced to an empty unit
  1242. Revision 1.17 2002/10/20 19:01:38 mazen
  1243. + op_raddr_reg and op_caddr_reg added to fix functions prologue
  1244. Revision 1.16 2002/10/13 21:46:07 mazen
  1245. * assembler output format fixed
  1246. Revision 1.15 2002/10/11 13:35:14 mazen
  1247. *** empty log message ***
  1248. Revision 1.14 2002/10/10 19:57:51 mazen
  1249. * Just to update repsitory
  1250. Revision 1.13 2002/10/10 15:10:39 mazen
  1251. * Internal error fixed, but usually i386 parameter model used
  1252. Revision 1.12 2002/10/08 17:17:03 mazen
  1253. *** empty log message ***
  1254. Revision 1.11 2002/10/07 20:33:04 mazen
  1255. word alignement modified in g_stack_frame
  1256. Revision 1.10 2002/10/04 21:57:42 mazen
  1257. * register allocation for parameters now done in cpupara
  1258. Revision 1.9 2002/10/02 22:20:28 mazen
  1259. + out registers allocator for the first 6 scalar parameters which must be passed into %o0..%o5
  1260. Revision 1.8 2002/10/01 21:35:58 mazen
  1261. + procedures exiting prologue added and stack frame now restored in the delay slot of the return (JMPL) instruction
  1262. Revision 1.7 2002/10/01 21:06:29 mazen
  1263. attinst.inc --> strinst.inc
  1264. Revision 1.6 2002/10/01 17:41:50 florian
  1265. * fixed log and id
  1266. }