cgcpu.pas 50 KB

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