cgcpu.pas 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578
  1. {******************************************************************************
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This program is free software;you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation;either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY;without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program;if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *****************************************************************************}
  16. UNIT cgcpu;
  17. {This unit implements the code generator for the SPARC architecture}
  18. {$INCLUDE fpcdefs.inc}
  19. INTERFACE
  20. USES
  21. cginfo,cgbase,cgobj,cg64f32,
  22. aasmbase,aasmtai,aasmcpu,
  23. cpubase,cpuinfo,cpupara,
  24. node,symconst;
  25. TYPE
  26. TCgSparc=CLASS(tcg)
  27. {This method is used to pass a parameter, which is located in a register, to a
  28. routine. It should give the parameter to the routine, as required by the
  29. specific processor ABI. It is overriden for each CPU target.
  30. Size : is the size of the operand in the register
  31. r : is the register source of the operand
  32. LocPara : is the location where the parameter will be stored}
  33. procedure a_param_reg(list:TAasmOutput;sz:tcgsize;r:tregister;const LocPara:TParaLocation);override;
  34. {passes a parameter which is a constant to a function}
  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_call_name(list:TAasmOutput;CONST s:string);override;
  39. procedure a_call_ref(list:TAasmOutput;CONST ref:TReference);override;
  40. procedure a_call_reg(list:TAasmOutput;Reg:TRegister);override;
  41. {Branch Instruction}
  42. procedure a_jmp_always(List:TAasmOutput;l:TAsmLabel);override;
  43. {General purpose instyructions}
  44. procedure a_op_const_reg(list:TAasmOutput;Op:TOpCG;a:AWord;reg:TRegister);override;
  45. procedure a_op_const_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;a:AWord;CONST ref:TReference);override;
  46. procedure a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);override;
  47. procedure a_op_ref_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;CONST ref:TReference;reg:TRegister);override;
  48. procedure a_op_reg_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;reg:TRegister;CONST ref:TReference);override;
  49. procedure a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aword;src, dst:tregister);override;
  50. procedure a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override;
  51. { move instructions }
  52. procedure a_load_const_reg(list:TAasmOutput;size:tcgsize;a:aword;reg:tregister);override;
  53. procedure a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;CONST ref:TReference);override;
  54. procedure a_load_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;CONST ref:TReference);override;
  55. procedure a_load_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);override;
  56. procedure a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);override;
  57. procedure a_loadaddr_ref_reg(list:TAasmOutput;CONST ref:TReference;r:tregister);override;
  58. { fpu move instructions }
  59. procedure a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);override;
  60. procedure a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);override;
  61. procedure a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;CONST ref:TReference);override;
  62. { vector register move instructions }
  63. procedure a_loadmm_reg_reg(list:TAasmOutput;reg1, reg2:tregister);override;
  64. procedure a_loadmm_ref_reg(list:TAasmOutput;CONST ref:TReference;reg:tregister);override;
  65. procedure a_loadmm_reg_ref(list:TAasmOutput;reg:tregister;CONST ref:TReference);override;
  66. procedure a_parammm_reg(list:TAasmOutput;reg:tregister);override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);override;
  69. procedure a_cmp_const_ref_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;CONST ref:TReference;l:tasmlabel);override;
  70. procedure a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override;
  71. procedure a_cmp_ref_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;CONST ref:TReference;reg:tregister;l:tasmlabel);override;
  72. procedure a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);{ override;}
  73. procedure a_jmp_flags(list:TAasmOutput;CONST f:TResFlags;l:tasmlabel);override;
  74. procedure g_flags2reg(list:TAasmOutput;Size:TCgSize;CONST f:tresflags;reg:TRegister);override;
  75. procedure g_overflowCheck(List:TAasmOutput;const p:TNode);override;
  76. procedure g_stackframe_entry(list:TAasmOutput;localsize:LongInt);override;
  77. procedure g_restore_all_registers(list:TAasmOutput;selfused,accused,acchiused:boolean);override;
  78. procedure g_restore_frame_pointer(list:TAasmOutput);override;
  79. procedure g_restore_standard_registers(list:taasmoutput;usedinproc:Tsupregset);override;
  80. procedure g_return_from_proc(list:TAasmOutput;parasize:aword);override;
  81. procedure g_save_all_registers(list : taasmoutput);override;
  82. procedure g_save_standard_registers(list : taasmoutput; usedinproc : Tsupregset);override;
  83. procedure g_concatcopy(list:TAasmOutput;CONST source,dest:TReference;len:aword;delsource,loadref:boolean);override;
  84. class function reg_cgsize(CONST reg:tregister):tcgsize;override;
  85. PRIVATE
  86. function IsSimpleRef(const ref:treference):boolean;
  87. procedure sizes2load(s1:tcgsize;s2:topsize;var op:tasmop;var s3:topsize);
  88. procedure floatload(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  89. procedure floatstore(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  90. procedure floatloadops(t:tcgsize;var op:tasmop;var s:topsize);
  91. procedure floatstoreops(t:tcgsize;var op:tasmop;var s:topsize);
  92. END;
  93. TCg64Sparc=class(tcg64f32)
  94. procedure a_op64_ref_reg(list:TAasmOutput;op:TOpCG;CONST ref:TReference;reg:TRegister64);override;
  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 a_op64_const_ref(list:TAasmOutput;op:TOpCG;value:qWord;CONST ref:TReference);override;
  98. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  99. END;
  100. CONST
  101. TOpCG2AsmOp:ARRAY[topcg]OF TAsmOp=(A_NONE,A_ADD,A_AND,A_UDIV,A_SDIV,A_UMUL, A_SMUL, A_NEG,A_NOT,A_OR,A_not,A_not,A_not,A_SUB,A_XOR);
  102. TOpCmp2AsmCond:ARRAY[topcmp]OF TAsmCond=(C_NONE,C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  103. TCGSize2OpSize:ARRAY[tcgsize]OF TOpSize=(S_NO,S_B,S_W,S_SW,S_SW,S_B,S_W,S_SW,S_SW,S_FS,S_FD,S_FQ,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  104. IMPLEMENTATION
  105. USES
  106. globtype,globals,verbose,systems,cutils,
  107. symdef,symsym,defutil,paramgr,
  108. rgobj,tgobj,rgcpu,cpupi;
  109. procedure TCgSparc.a_param_reg(list:TAasmOutput;sz:tcgsize;r:tregister;const LocPara:TParaLocation);
  110. var
  111. r2:Tregister;
  112. begin
  113. r2.enum:=R_G0;
  114. with list,LocPara do
  115. case Loc of
  116. LOC_REGISTER:
  117. case Sz of
  118. OS_8,OS_S8:
  119. Concat(taicpu.op_Reg_Const_Reg(A_AND,r,$FF,Register));
  120. OS_16,OS_S16:
  121. begin
  122. Concat(taicpu.op_Reg_Reg_Reg(A_AND,r,r2,Register));
  123. {This will put 00...00111 in the hiest 22 bits of the reg}
  124. Concat(taicpu.op_Reg_Const_Reg(A_SETHI,Register,$7,Register));
  125. end;
  126. OS_32,OS_S32:
  127. if r.enum<>Register.enum
  128. then
  129. Concat(taicpu.op_Reg_Reg_Reg(A_OR,r,r2,Register));
  130. else
  131. InternalError(2002032212);
  132. end;
  133. else
  134. InternalError(2002101002);
  135. end;
  136. end;
  137. procedure TCgSparc.a_param_const(list:TAasmOutput;size:tcgsize;a:aword;CONST LocPara:TParaLocation);
  138. var
  139. Ref:TReference;
  140. begin
  141. with List do
  142. case locpara.loc of
  143. LOC_REGISTER,LOC_CREGISTER:
  144. a_load_const_reg(list,size,a,locpara.register);
  145. LOC_REFERENCE:
  146. begin
  147. reference_reset(ref);
  148. ref.base:=locpara.reference.index;
  149. ref.offset:=locpara.reference.offset;
  150. a_load_const_ref(list,size,a,ref);
  151. end;
  152. else
  153. InternalError(2002122200);
  154. end;
  155. if locpara.sp_fixup<>0
  156. then
  157. InternalError(2002122201);
  158. end;
  159. procedure TCgSparc.a_param_ref(list:TAasmOutput;sz:TCgSize;const r:TReference;const LocPara:TParaLocation);
  160. var
  161. ref: treference;
  162. tmpreg:TRegister;
  163. begin
  164. with LocPara do
  165. case locpara.loc of
  166. LOC_REGISTER,LOC_CREGISTER:
  167. a_load_ref_reg(list,sz,r,Register);
  168. LOC_REFERENCE:
  169. begin
  170. {Code conventions need the parameters being allocated in %o6+92. See
  171. comment on g_stack_frame}
  172. if locpara.sp_fixup<92
  173. then
  174. InternalError(2002081104);
  175. reference_reset(ref);
  176. ref.base:=locpara.reference.index;
  177. ref.offset:=locpara.reference.offset;
  178. tmpreg := get_scratch_reg_int(list,sz);
  179. a_load_ref_reg(list,sz,r,tmpreg);
  180. a_load_reg_ref(list,sz,tmpreg,ref);
  181. free_scratch_reg(list,tmpreg);
  182. end;
  183. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  184. case sz of
  185. OS_32:
  186. a_loadfpu_ref_reg(list,OS_F32,r,locpara.register);
  187. OS_64:
  188. a_loadfpu_ref_reg(list,OS_F64,r,locpara.register);
  189. else
  190. internalerror(2002072801);
  191. end;
  192. else
  193. internalerror(2002081103);
  194. end;
  195. end;
  196. procedure TCgSparc.a_paramaddr_ref(list:TAasmOutput;CONST r:TReference;CONST LocPara:TParaLocation);
  197. var
  198. Ref:TReference;
  199. TmpReg:TRegister;
  200. begin
  201. case locpara.loc of
  202. LOC_REGISTER,LOC_CREGISTER:
  203. a_loadaddr_ref_reg(list,r,locpara.register);
  204. LOC_REFERENCE:
  205. begin
  206. reference_reset(ref);
  207. ref.base := locpara.reference.index;
  208. ref.offset := locpara.reference.offset;
  209. tmpreg := get_scratch_reg_address(list);
  210. a_loadaddr_ref_reg(list,r,tmpreg);
  211. a_load_reg_ref(list,OS_ADDR,tmpreg,ref);
  212. free_scratch_reg(list,tmpreg);
  213. end;
  214. else
  215. internalerror(2002080701);
  216. end;
  217. end;
  218. procedure TCgSparc.a_call_name(list:TAasmOutput;CONST s:string);
  219. BEGIN
  220. WITH List,objectlibrary DO
  221. BEGIN
  222. concat(taicpu.op_sym(A_CALL,S_SW,newasmsymbol(s)));
  223. concat(taicpu.op_none(A_NOP));
  224. END;
  225. END;
  226. procedure TCgSparc.a_call_ref(list:TAasmOutput;CONST ref:TReference);
  227. begin
  228. list.concat(taicpu.op_ref(A_CALL,ref));
  229. list.concat(taicpu.op_none(A_NOP));
  230. end;
  231. procedure TCgSparc.a_call_reg(list:TAasmOutput;Reg:TRegister);
  232. var
  233. RetAddrReg:TRegister;
  234. begin
  235. with RetAddrReg do
  236. begin
  237. enum:=R_INTREGISTER;
  238. Number:=NR_O7;
  239. end;
  240. list.concat(taicpu.op_reg_reg(A_JMPL,reg,RetAddrReg));
  241. if target_info.system=system_sparc_linux
  242. then
  243. list.concat(taicpu.op_none(A_NOP));
  244. include(current_procinfo.flags,pi_do_call);
  245. end;
  246. {********************** branch instructions ********************}
  247. procedure TCgSparc.a_jmp_always(List:TAasmOutput;l:TAsmLabel);
  248. begin
  249. List.Concat(TAiCpu.op_sym(A_BA,S_NO,objectlibrary.newasmsymbol(l.name)));
  250. end;
  251. {********************** load instructions ********************}
  252. procedure TCgSparc.a_load_const_reg(list:TAasmOutput;size:TCGSize;a:aword;reg:TRegister);
  253. var r:Tregister;
  254. BEGIN
  255. r.enum:=R_G0;
  256. WITH List DO
  257. IF a<>0
  258. THEN{R_G0 is usually set to zero, so we use it}
  259. Concat(taicpu.op_reg_const_reg(A_OR,r,a,reg))
  260. ELSE{The is no A_MOV in sparc, that's why we use A_OR with help of R_G0}
  261. Concat(taicpu.op_reg_reg_reg(A_OR,r,r,reg));
  262. END;
  263. procedure TCgSparc.a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aword;CONST ref:TReference);
  264. var r:Tregister;
  265. BEGIN
  266. r.enum:=R_G0;
  267. WITH List DO
  268. IF a=0
  269. THEN
  270. Concat(taicpu.op_reg_ref(A_ST,r,Ref))
  271. ELSE
  272. BEGIN
  273. r.enum:=R_G1;
  274. a_load_const_reg(list,size,a,r);
  275. a_load_reg_ref(list,size,r,Ref);
  276. END;
  277. END;
  278. procedure TCgSparc.a_load_reg_ref(list:TAasmOutput;size:TCGSize;reg:tregister;const Ref:TReference);
  279. var
  280. op:tasmop;
  281. begin
  282. case size of
  283. { signed integer registers }
  284. OS_S8:
  285. Op:=A_STB;{Store Signed Byte}
  286. OS_S16:
  287. Op:=A_STH;{Store Signed Halfword}
  288. OS_S32:
  289. Op:=A_ST;{Store Word}
  290. OS_S64:
  291. Op:=A_STD;{Store Double Word}
  292. { unsigned integer registers }
  293. //A_STSTUB;{Store-Store Unsigned Byte}
  294. OS_8:
  295. Op:=A_STB;{Store Unsigned Bye}
  296. OS_16:
  297. Op:=A_STH;{Store Unsigned Halfword}
  298. OS_32:
  299. Op:=A_ST;{Store Word}
  300. OS_64:
  301. Op:=A_STD;{Store Double Word}
  302. { floating-point real registers }
  303. OS_F32:
  304. Op:=A_STF;{Store Floating-point word}
  305. //A_STFSR
  306. OS_F64:
  307. Op:=A_STDF;{Store Double Floating-point word}
  308. //A_STC;{Store Coprocessor}
  309. //A_STCSR;
  310. //A_STDC;{Store Double Coprocessor}
  311. else
  312. InternalError(2002122100);
  313. end;
  314. with list do
  315. concat(taicpu.op_reg_ref(op,reg,ref));
  316. end;
  317. procedure TCgSparc.a_load_ref_reg(list:TAasmOutput;size:TCgSize;const ref:TReference;reg:tregister);
  318. var
  319. op:tasmop;
  320. begin
  321. case size of
  322. { signed integer registers }
  323. OS_S8:
  324. Op:=A_LDSB;{Load Signed Byte}
  325. OS_S16:
  326. Op:=A_LDSH;{Load Signed Halfword}
  327. OS_S32:
  328. Op:=A_LD;{Load Word}
  329. OS_S64:
  330. Op:=A_LDD;{Load Double Word}
  331. { unsigned integer registers }
  332. //A_LDSTUB;{Load-Store Unsigned Byte}
  333. OS_8:
  334. Op:=A_LDUB;{Load Unsigned Bye}
  335. OS_16:
  336. Op:=A_LDUH;{Load Unsigned Halfword}
  337. OS_32:
  338. Op:=A_LD;{Load Word}
  339. OS_64:
  340. Op:=A_LDD;{Load Double Word}
  341. { floating-point real registers }
  342. OS_F32:
  343. Op:=A_LDF;{Load Floating-point word}
  344. //A_LDFSR
  345. OS_F64:
  346. Op:=A_LDDF;{Load Double Floating-point word}
  347. //A_LDC;{Load Coprocessor}
  348. //A_LDCSR;
  349. //A_LDDC;{Load Double Coprocessor}
  350. else
  351. InternalError(2002122100);
  352. end;
  353. with list do
  354. concat(taicpu.op_ref_reg(op,ref,reg));
  355. end;
  356. procedure TCgSparc.a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister);
  357. var
  358. op:tasmop;
  359. s:topsize;
  360. r:Tregister;
  361. begin
  362. r.enum:=R_G0;
  363. if(reg1.enum<>reg2.enum)or
  364. (tcgsize2size[tosize]<tcgsize2size[fromsize])or
  365. ((tcgsize2size[tosize] = tcgsize2size[fromsize])and
  366. (tosize <> fromsize)and
  367. not(fromsize in [OS_32,OS_S32]))
  368. then
  369. with list do
  370. case fromsize of
  371. OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32:
  372. concat(taicpu.op_reg_reg_reg(A_OR,r,reg1,reg2));
  373. else internalerror(2002090901);
  374. end;
  375. end;
  376. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  377. { R_ST means "the current value at the top of the fpu stack" (JM) }
  378. procedure TCgSparc.a_loadfpu_reg_reg(list:TAasmOutput;reg1, reg2:tregister);
  379. begin
  380. { if NOT (reg1 IN [R_F0..R_F31]) then
  381. begin
  382. list.concat(taicpu.op_reg(A_NONE,S_NO,
  383. trgcpu(rg).correct_fpuregister(reg1,trgcpu(rg).fpuvaroffset)));
  384. inc(trgcpu(rg).fpuvaroffset);
  385. end;
  386. if NOT (reg2 IN [R_F0..R_F31]) then
  387. begin
  388. list.concat(taicpu.op_reg(A_JMPL,S_NO,
  389. trgcpu(rg).correct_fpuregister(reg2,trgcpu(rg).fpuvaroffset)));
  390. dec(trgcpu(rg).fpuvaroffset);
  391. end;}
  392. end;
  393. procedure TCgSparc.a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;CONST ref:TReference;reg:tregister);
  394. begin
  395. floatload(list,size,ref);
  396. { if (reg <> R_ST) then
  397. a_loadfpu_reg_reg(list,R_ST,reg);}
  398. end;
  399. procedure TCgSparc.a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);
  400. const
  401. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  402. { indexed? updating?}
  403. (((A_STF,A_STF),(A_STF,A_STF)),
  404. ((A_STDF,A_STDF),(A_STDF,A_STDF)));
  405. var
  406. op: tasmop;
  407. ref2: treference;
  408. freereg: boolean;
  409. begin
  410. if not(size in [OS_F32,OS_F64])
  411. then
  412. internalerror(200201122);
  413. { ref2:=ref;
  414. freereg:=fixref(list,ref2);
  415. op:=fpustoreinstr[size,ref2.index.enum <> R_NO,false];
  416. a_load_store(list,op,reg,ref2);
  417. if freereg
  418. then
  419. cg.free_scratch_reg(list,ref2.base);}
  420. end;
  421. procedure TCgSparc.a_loadmm_reg_reg(list:TAasmOutput;reg1, reg2:tregister);
  422. begin
  423. // list.concat(taicpu.op_reg_reg(A_NONEQ,S_NO,reg1,reg2));
  424. end;
  425. procedure TCgSparc.a_loadmm_ref_reg(list:TAasmOutput;CONST ref:TReference;reg:tregister);
  426. begin
  427. // list.concat(taicpu.op_ref_reg(A_NONEQ,S_NO,ref,reg));
  428. end;
  429. procedure TCgSparc.a_loadmm_reg_ref(list:TAasmOutput;reg:tregister;CONST ref:TReference);
  430. begin
  431. // list.concat(taicpu.op_reg_ref(A_NONEQ,S_NO,reg,ref));
  432. end;
  433. procedure TCgSparc.a_parammm_reg(list:TAasmOutput;reg:tregister);
  434. VAR
  435. href:TReference;
  436. BEGIN
  437. // list.concat(taicpu.op_const_reg(A_SUB,S_SW,8,R_RSP));
  438. // reference_reset_base(href,R_ESP,0);
  439. // list.concat(taicpu.op_reg_ref(A_NONEQ,S_NO,reg,href));
  440. END;
  441. procedure TCgSparc.a_op_const_reg(list:TAasmOutput;Op:TOpCG;a:AWord;reg:TRegister);
  442. var
  443. opcode:tasmop;
  444. power:LongInt;
  445. begin
  446. (* Case Op of
  447. OP_DIV, OP_IDIV:
  448. Begin
  449. if ispowerof2(a,power) then
  450. begin
  451. case op of
  452. OP_DIV:
  453. opcode := A_SHR;
  454. OP_IDIV:
  455. opcode := A_SAR;
  456. end;
  457. list.concat(taicpu.op_const_reg(opcode,S_SW,power,
  458. reg));
  459. exit;
  460. end;
  461. { the rest should be handled specifically in the code }
  462. { generator because of the silly register usage restraints }
  463. internalerror(200109224);
  464. End;
  465. OP_MUL,OP_IMUL:
  466. begin
  467. if not(cs_check_overflow in aktlocalswitches) and
  468. ispowerof2(a,power) then
  469. begin
  470. list.concat(taicpu.op_const_reg(A_SHL,S_SW,power,
  471. reg));
  472. exit;
  473. end;
  474. if op = OP_IMUL then
  475. list.concat(taicpu.op_const_reg(A_IMUL,S_SW,
  476. a,reg))
  477. else
  478. { OP_MUL should be handled specifically in the code }
  479. { generator because of the silly register usage restraints }
  480. internalerror(200109225);
  481. end;
  482. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  483. if not(cs_check_overflow in aktlocalswitches) and
  484. (a = 1) and
  485. (op in [OP_ADD,OP_SUB]) then
  486. if op = OP_ADD then
  487. list.concat(taicpu.op_reg(A_INC,S_SW,reg))
  488. else
  489. list.concat(taicpu.op_reg(A_DEC,S_SW,reg))
  490. else if (a = 0) then
  491. if (op <> OP_AND) then
  492. exit
  493. else
  494. list.concat(taicpu.op_const_reg(A_NONE,S_SW,0,reg))
  495. else if (a = high(aword)) and
  496. (op in [OP_AND,OP_OR,OP_XOR]) then
  497. begin
  498. case op of
  499. OP_AND:
  500. exit;
  501. OP_OR:
  502. list.concat(taicpu.op_const_reg(A_NONE,S_SW,high(aword),reg));
  503. OP_XOR:
  504. list.concat(taicpu.op_reg(A_NOT,S_SW,reg));
  505. end
  506. end
  507. else
  508. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],S_SW,
  509. a,reg));
  510. OP_SHL,OP_SHR,OP_SAR:
  511. begin
  512. if (a and 31) <> 0 Then
  513. list.concat(taicpu.op_const_reg(
  514. TOpCG2AsmOp[op],S_SW,a and 31,reg));
  515. if (a shr 5) <> 0 Then
  516. internalerror(68991);
  517. end
  518. else internalerror(68992);
  519. end;*)
  520. end;
  521. procedure TCgSparc.a_op_const_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;a:AWord;CONST ref:TReference);
  522. var
  523. opcode:tasmop;
  524. power:LongInt;
  525. begin
  526. (* Case Op of
  527. OP_DIV, OP_IDIV:
  528. Begin
  529. if ispowerof2(a,power) then
  530. begin
  531. case op of
  532. OP_DIV:
  533. opcode := A_SHR;
  534. OP_IDIV:
  535. opcode := A_SAR;
  536. end;
  537. list.concat(taicpu.op_const_ref(opcode,
  538. TCgSize2OpSize[size],power,ref));
  539. exit;
  540. end;
  541. { the rest should be handled specifically in the code }
  542. { generator because of the silly register usage restraints }
  543. internalerror(200109231);
  544. End;
  545. OP_MUL,OP_IMUL:
  546. begin
  547. if not(cs_check_overflow in aktlocalswitches) and
  548. ispowerof2(a,power) then
  549. begin
  550. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  551. power,ref));
  552. exit;
  553. end;
  554. { can't multiply a memory location directly with a CONSTant }
  555. if op = OP_IMUL then
  556. inherited a_op_const_ref(list,op,size,a,ref)
  557. else
  558. { OP_MUL should be handled specifically in the code }
  559. { generator because of the silly register usage restraints }
  560. internalerror(200109232);
  561. end;
  562. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  563. if not(cs_check_overflow in aktlocalswitches) and
  564. (a = 1) and
  565. (op in [OP_ADD,OP_SUB]) then
  566. if op = OP_ADD then
  567. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  568. else
  569. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  570. else if (a = 0) then
  571. if (op <> OP_AND) then
  572. exit
  573. else
  574. a_load_const_ref(list,size,0,ref)
  575. else if (a = high(aword)) and
  576. (op in [OP_AND,OP_OR,OP_XOR]) then
  577. begin
  578. case op of
  579. OP_AND:
  580. exit;
  581. OP_OR:
  582. list.concat(taicpu.op_const_ref(A_NONE,TCgSize2OpSize[size],high(aword),ref));
  583. OP_XOR:
  584. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  585. end
  586. end
  587. else
  588. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  589. TCgSize2OpSize[size],a,ref));
  590. OP_SHL,OP_SHR,OP_SAR:
  591. begin
  592. if (a and 31) <> 0 Then
  593. list.concat(taicpu.op_const_ref(
  594. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  595. if (a shr 5) <> 0 Then
  596. internalerror(68991);
  597. end
  598. else internalerror(68992);
  599. end;*)
  600. end;
  601. procedure TCgSparc.a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);
  602. var
  603. regloadsize:tcgsize;
  604. dstsize:topsize;
  605. tmpreg:tregister;
  606. popecx:boolean;
  607. begin
  608. (* dstsize := S_Q{makeregsize(dst,size)};
  609. case op of
  610. OP_NEG,OP_NOT:
  611. begin
  612. if src <> R_NO then
  613. internalerror(200112291);
  614. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  615. end;
  616. OP_MUL,OP_DIV,OP_IDIV:
  617. { special stuff, needs separate handling inside code }
  618. { generator }
  619. internalerror(200109233);
  620. OP_SHR,OP_SHL,OP_SAR:
  621. begin
  622. tmpreg := R_NO;
  623. { we need cl to hold the shift count, so if the destination }
  624. { is ecx, save it to a temp for now }
  625. if dst in [R_ECX,R_CX,R_CL] then
  626. begin
  627. case S_SW of
  628. S_B:regloadsize := OS_8;
  629. S_W:regloadsize := OS_16;
  630. else regloadsize := OS_32;
  631. end;
  632. tmpreg := get_scratch_reg(list);
  633. a_load_reg_reg(list,regloadsize,OS_32,src,tmpreg);
  634. end;
  635. if not(src in [R_ECX,R_CX,R_CL]) then
  636. begin
  637. { is ecx still free (it's also free if it was allocated }
  638. { to dst, since we've moved dst somewhere else already) }
  639. if not((dst = R_ECX) or
  640. ((R_ECX in rg.unusedregsint) and
  641. { this will always be true, it's just here to }
  642. { allocate ecx }
  643. (rg.getexplicitregisterint(list,R_ECX) = R_ECX))) then
  644. begin
  645. list.concat(taicpu.op_reg(A_NONE,S_SW,R_ECX));
  646. popecx := true;
  647. end;
  648. a_load_reg_reg(list,OS_8,OS_8,(src),R_CL);
  649. end
  650. else
  651. src := R_CL;
  652. { do the shift }
  653. if tmpreg = R_NO then
  654. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  655. R_CL,dst))
  656. else
  657. begin
  658. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_SW,
  659. R_CL,tmpreg));
  660. { move result back to the destination }
  661. a_load_reg_reg(list,OS_32,OS_32,tmpreg,R_ECX);
  662. free_scratch_reg(list,tmpreg);
  663. end;
  664. if popecx then
  665. list.concat(taicpu.op_reg(A_POP,S_SW,R_ECX))
  666. else if not (dst in [R_ECX,R_CX,R_CL]) then
  667. rg.ungetregisterint(list,R_ECX);
  668. end;
  669. else
  670. begin
  671. if S_SW <> dstsize then
  672. internalerror(200109226);
  673. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  674. src,dst));
  675. end;
  676. end;*)
  677. end;
  678. procedure TCgSparc.a_op_ref_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;CONST ref:TReference;reg:TRegister);
  679. var
  680. opsize:topsize;
  681. begin
  682. (* case op of
  683. OP_NEG,OP_NOT,OP_IMUL:
  684. begin
  685. inherited a_op_ref_reg(list,op,size,ref,reg);
  686. end;
  687. OP_MUL,OP_DIV,OP_IDIV:
  688. { special stuff, needs separate handling inside code }
  689. { generator }
  690. internalerror(200109239);
  691. else
  692. begin
  693. opsize := S_Q{makeregsize(reg,size)};
  694. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],opsize,ref,reg));
  695. end;
  696. end;*)
  697. end;
  698. procedure TCgSparc.a_op_reg_ref(list:TAasmOutput;Op:TOpCG;size:TCGSize;reg:TRegister;CONST ref:TReference);
  699. var
  700. opsize:topsize;
  701. begin
  702. (* case op of
  703. OP_NEG,OP_NOT:
  704. begin
  705. if reg <> R_NO then
  706. internalerror(200109237);
  707. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  708. end;
  709. OP_IMUL:
  710. begin
  711. { this one needs a load/imul/store, which is the default }
  712. inherited a_op_ref_reg(list,op,size,ref,reg);
  713. end;
  714. OP_MUL,OP_DIV,OP_IDIV:
  715. { special stuff, needs separate handling inside code }
  716. { generator }
  717. internalerror(200109238);
  718. else
  719. begin
  720. opsize := tcgsize2opsize[size];
  721. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,ref));
  722. end;
  723. end;*)
  724. end;
  725. procedure TCgSparc.a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;
  726. size:tcgsize;a:aword;src, dst:tregister);
  727. var
  728. tmpref:TReference;
  729. power:LongInt;
  730. opsize:topsize;
  731. begin
  732. opsize := S_SW;
  733. if (opsize <> S_SW) or
  734. not (size in [OS_32,OS_S32]) then
  735. begin
  736. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  737. exit;
  738. end;
  739. { if we get here, we have to do a 32 bit calculation, guaranteed }
  740. Case Op of
  741. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  742. OP_SAR:
  743. { can't do anything special for these }
  744. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  745. OP_IMUL:
  746. begin
  747. if not(cs_check_overflow in aktlocalswitches) and
  748. ispowerof2(a,power) then
  749. { can be done with a shift }
  750. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  751. list.concat(taicpu.op_reg_const_reg(A_SMUL,src,a,dst));
  752. end;
  753. OP_ADD, OP_SUB:
  754. if (a = 0) then
  755. a_load_reg_reg(list,size,size,src,dst)
  756. else
  757. begin
  758. reference_reset(tmpref);
  759. tmpref.base := src;
  760. tmpref.offset := LongInt(a);
  761. if op = OP_SUB then
  762. tmpref.offset := -tmpref.offset;
  763. list.concat(taicpu.op_ref_reg(A_NONE,tmpref,dst));
  764. end
  765. else internalerror(200112302);
  766. end;
  767. end;
  768. procedure TCgSparc.a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;
  769. size:tcgsize;src1, src2, dst:tregister);
  770. var
  771. tmpref:TReference;
  772. opsize:topsize;
  773. begin
  774. opsize := S_SW;
  775. if (opsize <> S_SW) or
  776. (S_SW <> S_SW) or
  777. not (size in [OS_32,OS_S32]) then
  778. begin
  779. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  780. exit;
  781. end;
  782. { if we get here, we have to do a 32 bit calculation, guaranteed }
  783. Case Op of
  784. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  785. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  786. { can't do anything special for these }
  787. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  788. OP_IMUL:
  789. list.concat(taicpu.op_reg_reg_reg(A_SMUL,src1,src2,dst));
  790. OP_ADD:
  791. begin
  792. reference_reset(tmpref);
  793. tmpref.base := src1;
  794. tmpref.index := src2;
  795. tmpref.scalefactor := 1;
  796. list.concat(taicpu.op_ref_reg(A_NONE,tmpref,dst));
  797. end
  798. else internalerror(200112303);
  799. end;
  800. end;
  801. {*************** compare instructructions ****************}
  802. procedure TCgSparc.a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;reg:tregister;l:tasmlabel);
  803. begin
  804. if(a=0)
  805. then
  806. list.concat(taicpu.op_reg_reg(A_CMP,reg,reg))
  807. else
  808. list.concat(taicpu.op_const_reg(A_CMP,a,reg));
  809. a_jmp_cond(list,cmp_op,l);
  810. end;
  811. procedure TCgSparc.a_cmp_const_ref_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aword;const ref:TReference;l:tasmlabel);
  812. var
  813. cReg,rReg:TRegister;
  814. begin
  815. with cg do
  816. begin
  817. cReg:=get_scratch_reg_int(List,size);
  818. rReg:=get_scratch_reg_int(List,size);
  819. a_load_const_reg(List,OS_32,a,cReg);
  820. a_load_ref_reg(List,OS_32,ref,rReg);
  821. List.Concat(taicpu.op_reg_reg(A_CMP,rReg,cReg));
  822. a_jmp_cond(list,cmp_op,l);
  823. free_scratch_reg(List,cReg);
  824. free_scratch_reg(List,rReg);
  825. end;
  826. end;
  827. procedure TCgSparc.a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;
  828. reg1,reg2:tregister;l:tasmlabel);
  829. begin
  830. { if regsize(reg1) <> S_SW then
  831. internalerror(200109226);
  832. list.concat(taicpu.op_reg_reg(A_CMP,regsize(reg1),reg1,reg2));
  833. a_jmp_cond(list,cmp_op,l);}
  834. end;
  835. procedure TCgSparc.a_cmp_ref_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;CONST ref:TReference;reg:tregister;l:tasmlabel);
  836. var
  837. TempReg:TRegister;
  838. begin
  839. TempReg:=cg.get_scratch_reg_int(List,size);
  840. a_load_ref_reg(list,OS_32,Ref,TempReg);
  841. list.concat(taicpu.op_reg_reg_reg(A_SUBcc,TempReg,Reg,CpuReg[R_G0]));
  842. a_jmp_cond(list,cmp_op,l);
  843. cg.free_scratch_reg(exprasmlist,TempReg);
  844. end;
  845. procedure TCgSparc.a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:TAsmLabel);
  846. var
  847. ai:TAiCpu;
  848. begin
  849. ai:=TAiCpu.Op_sym(A_BA,S_NO,l);
  850. ai.SetCondition(TOpCmp2AsmCond[cond]);
  851. with List do
  852. begin
  853. Concat(ai);
  854. Concat(TAiCpu.Op_none(A_NOP));
  855. end;
  856. end;
  857. procedure TCgSparc.a_jmp_flags(list:TAasmOutput;CONST f:TResFlags;l:tasmlabel);
  858. var
  859. ai:taicpu;
  860. begin
  861. ai := Taicpu.op_sym(A_JMPL,S_NO,l);
  862. ai.SetCondition(flags_to_cond(f));
  863. with List do
  864. begin
  865. Concat(ai);
  866. Concat(TAiCpu.Op_none(A_NOP));
  867. end;
  868. end;
  869. procedure TCgSparc.g_flags2reg(list:TAasmOutput;Size:TCgSize;CONST f:tresflags;reg:TRegister);
  870. VAR
  871. ai:taicpu;
  872. r,hreg:tregister;
  873. BEGIN
  874. r.enum:=R_PSR;
  875. hreg := rg.makeregsize(reg,OS_8);
  876. ai:=Taicpu.Op_reg_reg(A_RDPSR,r,hreg);
  877. ai.SetCondition(flags_to_cond(f));
  878. with List do
  879. begin
  880. Concat(ai);
  881. Concat(TAiCpu.Op_none(A_NOP));
  882. end;
  883. IF hreg.enum<>reg.enum
  884. THEN
  885. a_load_reg_reg(list,OS_32,OS_32,hreg,reg);
  886. END;
  887. procedure TCgSparc.g_overflowCheck(List:TAasmOutput;const p:TNode);
  888. var
  889. hl:TAsmLabel;
  890. r:Tregister;
  891. begin
  892. r.enum:=R_NONE;
  893. if not(cs_check_overflow in aktlocalswitches)
  894. then
  895. exit;
  896. objectlibrary.getlabel(hl);
  897. if not((p.resulttype.def.deftype=pointerdef) or
  898. ((p.resulttype.def.deftype=orddef) and
  899. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  900. bool8bit,bool16bit,bool32bit])))
  901. then
  902. begin
  903. list.concat(taicpu.op_reg(A_NONE,r));
  904. a_jmp_always(list,hl)
  905. end
  906. else
  907. a_jmp_cond(list,OC_NONE,hl);
  908. a_call_name(list,'FPC_OVERFLOW');
  909. a_label(list,hl);
  910. end;
  911. { *********** entry/exit code and address loading ************ }
  912. procedure TCgSparc.g_stackframe_entry(list:TAasmOutput;LocalSize:LongInt);
  913. var
  914. href:TReference;
  915. r:Tregister;
  916. i:integer;
  917. again:tasmlabel;
  918. begin
  919. {Althogh the SPARC architecture require only word alignment, software
  920. convention and the operating system require every stack frame to be double word
  921. aligned}
  922. LocalSize:=(LocalSize+7)and $FFFFFFF8;
  923. {Execute the SAVE instruction to get a new register window and create a new
  924. stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state
  925. before execution of the SAVE instrucion so it is the caller %i6, when the %i6
  926. after execution of that instruction is the called function stack pointer}
  927. r.enum:=stack_pointer_reg;
  928. with list do
  929. concat(Taicpu.Op_reg_const_reg(A_SAVE,r,-LocalSize,r));
  930. end;
  931. procedure TCgSparc.g_restore_all_registers(list:TaasmOutput;selfused,accused,acchiused:boolean);
  932. begin
  933. {$warning FIX ME TCgSparc.g_restore_all_registers}
  934. end;
  935. procedure TCgSparc.g_restore_frame_pointer(list:TAasmOutput);
  936. begin
  937. {This function intontionally does nothing as frame pointer is restored in the
  938. delay slot of the return instrucion done in g_return_from_proc}
  939. end;
  940. procedure TCgSparc.g_restore_standard_registers(list:taasmoutput;usedinproc:Tsupregset);
  941. begin
  942. {$WARNING FIX ME TCgSparc.g_restore_standard_registers}
  943. end;
  944. procedure TCgSparc.g_return_from_proc(list:TAasmOutput;parasize:aword);
  945. var r,r2:Tregister;
  946. begin
  947. {According to the SPARC ABI, the stack is cleared using the RESTORE instruction
  948. which is genereted in the g_restore_frame_pointer. Notice that SPARC has no
  949. RETURN instruction and that JMPL is used instead. The JMPL instrucion have one
  950. delay slot, so an inversion is possible such as
  951. JMPL %i7+8,%g0
  952. RESTORE %g0,0,%g0
  953. If no inversion we can use just
  954. RESTORE %g0,0,%g0
  955. JMPL %i7+8,%g0
  956. NOP}
  957. with list do
  958. begin
  959. {Return address is computed by adding 8 to the CALL address saved onto %i6}
  960. r.enum:=R_G0;
  961. r2.enum:=R_I7;
  962. concat(Taicpu.Op_caddr_reg(A_JMPL,r,8,r));
  963. {We use trivial restore in the delay slot of the JMPL instruction, as we
  964. already set result onto %i0}
  965. concat(Taicpu.Op_reg_const_reg(A_RESTORE,r,0,r));
  966. end
  967. end;
  968. procedure TCgSparc.g_save_all_registers(list : taasmoutput);
  969. begin
  970. {$warning FIX ME TCgSparc.g_save_all_registers}
  971. end;
  972. procedure TCgSparc.g_save_standard_registers(list : taasmoutput; usedinproc:Tsupregset);
  973. begin
  974. {$warning FIX ME tcgppc.g_save_standard_registers}
  975. end;
  976. procedure TCgSparc.a_loadaddr_ref_reg(list:TAasmOutput;CONST ref:TReference;r:tregister);
  977. begin
  978. // list.concat(taicpu.op_ref_reg(A_LEA,S_SW,ref,r));
  979. end;
  980. { ************* 64bit operations ************ }
  981. procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  982. begin
  983. case op of
  984. OP_ADD :
  985. begin
  986. op1:=A_ADD;
  987. op2:=A_ADD;
  988. end;
  989. OP_SUB :
  990. begin
  991. op1:=A_SUB;
  992. op2:=A_SUB;
  993. end;
  994. OP_XOR :
  995. begin
  996. op1:=A_XOR;
  997. op2:=A_XOR;
  998. end;
  999. OP_OR :
  1000. begin
  1001. op1:=A_OR;
  1002. op2:=A_OR;
  1003. end;
  1004. OP_AND :
  1005. begin
  1006. op1:=A_AND;
  1007. op2:=A_AND;
  1008. end;
  1009. else
  1010. internalerror(200203241);
  1011. end;
  1012. end;
  1013. procedure TCg64Sparc.a_op64_ref_reg(list:TAasmOutput;op:TOpCG;CONST ref:TReference;reg:TRegister64);
  1014. var
  1015. op1,op2:TAsmOp;
  1016. tempref:TReference;
  1017. begin
  1018. get_64bit_ops(op,op1,op2);
  1019. list.concat(taicpu.op_ref_reg(op1,ref,reg.reglo));
  1020. tempref:=ref;
  1021. inc(tempref.offset,4);
  1022. list.concat(taicpu.op_ref_reg(op2,tempref,reg.reghi));
  1023. end;
  1024. procedure TCg64Sparc.a_op64_reg_reg(list:TAasmOutput;op:TOpCG;regsrc,regdst:TRegister64);
  1025. var
  1026. op1,op2:TAsmOp;
  1027. begin
  1028. get_64bit_ops(op,op1,op2);
  1029. list.concat(taicpu.op_reg_reg(op1,regsrc.reglo,regdst.reglo));
  1030. list.concat(taicpu.op_reg_reg(op2,regsrc.reghi,regdst.reghi));
  1031. end;
  1032. procedure TCg64Sparc.a_op64_const_reg(list:TAasmOutput;op:TOpCG;value:qWord;regdst:TRegister64);
  1033. var
  1034. op1,op2:TAsmOp;
  1035. begin
  1036. case op of
  1037. OP_AND,OP_OR,OP_XOR:
  1038. WITH cg DO
  1039. begin
  1040. a_op_const_reg(list,op,Lo(Value),regdst.reglo);
  1041. a_op_const_reg(list,op,Hi(Value),regdst.reghi);
  1042. end;
  1043. OP_ADD, OP_SUB:
  1044. begin
  1045. {can't use a_op_const_ref because this may use dec/inc}
  1046. get_64bit_ops(op,op1,op2);
  1047. list.concat(taicpu.op_const_reg(op1,Lo(Value),regdst.reglo));
  1048. list.concat(taicpu.op_const_reg(op2,Hi(Value),regdst.reghi));
  1049. end;
  1050. else
  1051. internalerror(200204021);
  1052. end;
  1053. end;
  1054. procedure TCg64Sparc.a_op64_const_ref(list:TAasmOutput;op:TOpCG;value:qWord;const ref:TReference);
  1055. var
  1056. op1,op2:TAsmOp;
  1057. tempref:TReference;
  1058. begin
  1059. case op of
  1060. OP_AND,OP_OR,OP_XOR:
  1061. with cg do
  1062. begin
  1063. a_op_const_ref(list,op,OS_32,Lo(Value),ref);
  1064. tempref:=ref;
  1065. inc(tempref.offset,4);
  1066. a_op_const_ref(list,op,OS_32,Hi(Value),tempref);
  1067. end;
  1068. OP_ADD, OP_SUB:
  1069. begin
  1070. get_64bit_ops(op,op1,op2);
  1071. { can't use a_op_const_ref because this may use dec/inc}
  1072. { list.concat(taicpu.op_const_ref(op1,Lo(Value),ref));
  1073. tempref:=ref;
  1074. inc(tempref.offset,4);
  1075. list.concat(taicpu.op_const_ref(op2,S_SW,Hi(Value),tempref));}
  1076. InternalError(2002102101);
  1077. end;
  1078. else
  1079. internalerror(200204022);
  1080. end;
  1081. end;
  1082. { ************* concatcopy ************ }
  1083. procedure TCgSparc.g_concatcopy(list:taasmoutput;const source,dest:treference;len:aword;delsource,loadref:boolean);
  1084. var
  1085. countreg: TRegister;
  1086. src, dst: TReference;
  1087. lab: tasmlabel;
  1088. count, count2: aword;
  1089. orgsrc, orgdst: boolean;
  1090. r:Tregister;
  1091. begin
  1092. {$ifdef extdebug}
  1093. if len > high(longint)
  1094. then
  1095. internalerror(2002072704);
  1096. {$endif extdebug}
  1097. { make sure short loads are handled as optimally as possible }
  1098. if not loadref
  1099. then
  1100. if(len <= 8)and(byte(len) in [1,2,4,8])
  1101. then
  1102. begin
  1103. if len < 8
  1104. then
  1105. begin
  1106. a_load_ref_ref(list,int_cgsize(len),source,dest);
  1107. if delsource
  1108. then
  1109. reference_release(list,source);
  1110. end
  1111. else
  1112. begin
  1113. r.enum:=R_F0;
  1114. a_reg_alloc(list,r);
  1115. a_loadfpu_ref_reg(list,OS_F64,source,r);
  1116. if delsource
  1117. then
  1118. reference_release(list,source);
  1119. a_loadfpu_reg_ref(list,OS_F64,r,dest);
  1120. a_reg_dealloc(list,r);
  1121. end;
  1122. exit;
  1123. end;
  1124. reference_reset(src);
  1125. reference_reset(dst);
  1126. { load the address of source into src.base }
  1127. if loadref
  1128. then
  1129. begin
  1130. src.base := get_scratch_reg_address(list);
  1131. a_load_ref_reg(list,OS_32,source,src.base);
  1132. orgsrc := false;
  1133. end
  1134. else if not issimpleref(source) or
  1135. ((source.index.enum<>R_NO)and
  1136. ((source.offset+longint(len))>high(smallint)))
  1137. then
  1138. begin
  1139. src.base := get_scratch_reg_address(list);
  1140. a_loadaddr_ref_reg(list,source,src.base);
  1141. orgsrc := false;
  1142. end
  1143. else
  1144. begin
  1145. src := source;
  1146. orgsrc := true;
  1147. end;
  1148. if not orgsrc and delsource
  1149. then
  1150. reference_release(list,source);
  1151. { load the address of dest into dst.base }
  1152. if not issimpleref(dest) or
  1153. ((dest.index.enum <> R_NO) and
  1154. ((dest.offset + longint(len)) > high(smallint)))
  1155. then
  1156. begin
  1157. dst.base := get_scratch_reg_address(list);
  1158. a_loadaddr_ref_reg(list,dest,dst.base);
  1159. orgdst := false;
  1160. end
  1161. else
  1162. begin
  1163. dst := dest;
  1164. orgdst := true;
  1165. end;
  1166. count:=len and 7;{count:=len div 8}
  1167. if count>4
  1168. then
  1169. { generate a loop }
  1170. begin
  1171. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1172. { have to be set to 8. I put an Inc there so debugging may be }
  1173. { easier (should offset be different from zero here, it will be }
  1174. { easy to notice in the generated assembler }
  1175. inc(dst.offset,8);
  1176. inc(src.offset,8);
  1177. list.concat(taicpu.op_reg_const_reg(A_SUB,src.base,8,src.base));
  1178. list.concat(taicpu.op_reg_const_reg(A_SUB,dst.base,8,dst.base));
  1179. countreg := get_scratch_reg_int(list,OS_32);
  1180. a_load_const_reg(list,OS_32,count,countreg);
  1181. { explicitely allocate R_O0 since it can be used safely here }
  1182. { (for holding date that's being copied) }
  1183. r.enum:=R_F0;
  1184. a_reg_alloc(list,r);
  1185. objectlibrary.getlabel(lab);
  1186. a_label(list, lab);
  1187. list.concat(taicpu.op_reg_const_reg(A_SUB,countreg,1,countreg));
  1188. list.concat(taicpu.op_ref_reg(A_LDF,src,r));
  1189. list.concat(taicpu.op_reg_ref(A_STD,r,dst));
  1190. //a_jmp(list,A_BC,C_NE,0,lab);
  1191. free_scratch_reg(list,countreg);
  1192. a_reg_dealloc(list,r);
  1193. len := len mod 8;
  1194. end;
  1195. count:=len and 7;
  1196. if count>0
  1197. then
  1198. { unrolled loop }
  1199. begin
  1200. r.enum:=R_F0;
  1201. a_reg_alloc(list,r);
  1202. for count2 := 1 to count do
  1203. begin
  1204. a_loadfpu_ref_reg(list,OS_F64,src,r);
  1205. a_loadfpu_reg_ref(list,OS_F64,r,dst);
  1206. inc(src.offset,8);
  1207. inc(dst.offset,8);
  1208. end;
  1209. a_reg_dealloc(list,r);
  1210. len := len mod 8;
  1211. end;
  1212. if (len and 4) <> 0 then
  1213. begin
  1214. r.enum:=R_O0;
  1215. a_reg_alloc(list,r);
  1216. a_load_ref_reg(list,OS_32,src,r);
  1217. a_load_reg_ref(list,OS_32,r,dst);
  1218. inc(src.offset,4);
  1219. inc(dst.offset,4);
  1220. a_reg_dealloc(list,r);
  1221. end;
  1222. { copy the leftovers }
  1223. if (len and 2) <> 0 then
  1224. begin
  1225. r.enum:=R_O0;
  1226. a_reg_alloc(list,r);
  1227. a_load_ref_reg(list,OS_16,src,r);
  1228. a_load_reg_ref(list,OS_16,r,dst);
  1229. inc(src.offset,2);
  1230. inc(dst.offset,2);
  1231. a_reg_dealloc(list,r);
  1232. end;
  1233. if (len and 1) <> 0 then
  1234. begin
  1235. r.enum:=R_O0;
  1236. a_reg_alloc(list,r);
  1237. a_load_ref_reg(list,OS_8,src,r);
  1238. a_load_reg_ref(list,OS_8,r,dst);
  1239. a_reg_dealloc(list,r);
  1240. end;
  1241. if orgsrc then
  1242. begin
  1243. if delsource then
  1244. reference_release(list,source);
  1245. end
  1246. else
  1247. free_scratch_reg(list,src.base);
  1248. if not orgdst then
  1249. free_scratch_reg(list,dst.base);
  1250. end;
  1251. function TCgSparc.reg_cgsize(CONST reg:tregister):tcgsize;
  1252. begin
  1253. result:=OS_32;
  1254. end;
  1255. {***************** This is private property, keep out! :) *****************}
  1256. function TCgSparc.IsSimpleRef(const ref:treference):boolean;
  1257. begin
  1258. if(ref.base.enum=R_NONE)and(ref.index.enum <> R_NO)
  1259. then
  1260. InternalError(2002100804);
  1261. result :=not(assigned(ref.symbol))and
  1262. (((ref.index.enum = R_NO) and
  1263. (ref.offset >= low(smallint)) and
  1264. (ref.offset <= high(smallint))) or
  1265. ((ref.index.enum <> R_NO) and
  1266. (ref.offset = 0)));
  1267. end;
  1268. procedure TCgSparc.sizes2load(s1:tcgsize;s2:topsize;var op:tasmop;var s3:topsize);
  1269. begin
  1270. case s2 of
  1271. S_B:
  1272. if S1 in [OS_8,OS_S8]
  1273. then
  1274. s3 := S_B
  1275. else
  1276. internalerror(200109221);
  1277. S_W:
  1278. case s1 of
  1279. OS_8,OS_S8:
  1280. s3 := S_B;
  1281. OS_16,OS_S16:
  1282. s3 := S_H;
  1283. else
  1284. internalerror(200109222);
  1285. end;
  1286. S_SW:
  1287. case s1 of
  1288. OS_8,OS_S8:
  1289. s3 := S_B;
  1290. OS_16,OS_S16:
  1291. s3 := S_H;
  1292. OS_32,OS_S32:
  1293. s3 := S_W;
  1294. else
  1295. internalerror(200109223);
  1296. end;
  1297. else internalerror(200109227);
  1298. end;
  1299. if s3 in [S_B,S_W,S_SW]
  1300. then
  1301. op := A_LD
  1302. { else if s3=S_DW
  1303. then
  1304. op:=A_LDD
  1305. else if s3 in [OS_8,OS_16,OS_32]
  1306. then
  1307. op := A_NONE}
  1308. else
  1309. op := A_NONE;
  1310. end;
  1311. procedure TCgSparc.floatloadops(t:tcgsize;VAR op:tasmop;VAR s:topsize);
  1312. BEGIN
  1313. (* case t of
  1314. OS_F32:begin
  1315. op:=A_FLD;
  1316. s:=S_FS;
  1317. end;
  1318. OS_F64:begin
  1319. op:=A_FLD;
  1320. { ???? }
  1321. s:=S_FL;
  1322. end;
  1323. OS_F80:begin
  1324. op:=A_FLD;
  1325. s:=S_FX;
  1326. end;
  1327. OS_C64:begin
  1328. op:=A_FILD;
  1329. s:=S_IQ;
  1330. end;
  1331. else internalerror(17);
  1332. end;*)
  1333. END;
  1334. procedure TCgSparc.floatload(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  1335. VAR
  1336. op:tasmop;
  1337. s:topsize;
  1338. BEGIN
  1339. floatloadops(t,op,s);
  1340. list.concat(Taicpu.Op_ref(op,ref));
  1341. { inc(trgcpu(rg).fpuvaroffset);}
  1342. END;
  1343. procedure TCgSparc.floatstoreops(t:tcgsize;var op:tasmop;var s:topsize);
  1344. BEGIN
  1345. { case t of
  1346. OS_F32:begin
  1347. op:=A_FSTP;
  1348. s:=S_FS;
  1349. end;
  1350. OS_F64:begin
  1351. op:=A_FSTP;
  1352. s:=S_FL;
  1353. end;
  1354. OS_F80:begin
  1355. op:=A_FSTP;
  1356. s:=S_FX;
  1357. end;
  1358. OS_C64:begin
  1359. op:=A_FISTP;
  1360. s:=S_IQ;
  1361. end;
  1362. else
  1363. internalerror(17);
  1364. end;}
  1365. end;
  1366. procedure TCgSparc.floatstore(list:TAasmOutput;t:tcgsize;CONST ref:TReference);
  1367. VAR
  1368. op:tasmop;
  1369. s:topsize;
  1370. BEGIN
  1371. floatstoreops(t,op,s);
  1372. list.concat(Taicpu.Op_ref(op,ref));
  1373. { dec(trgcpu(rg).fpuvaroffset);}
  1374. END;
  1375. BEGIN
  1376. cg:=TCgSparc.Create;
  1377. cg64:=TCg64Sparc.Create;
  1378. END.
  1379. {
  1380. $Log$
  1381. Revision 1.45 2003-04-29 11:58:21 mazen
  1382. * fixed bug of output generated assembler for a_cmp_const_ref_label
  1383. Revision 1.44 2003/04/28 09:44:42 mazen
  1384. + NOP after conditional jump instruction to prevent delay slot execution
  1385. Revision 1.43 2003/04/27 11:21:36 peter
  1386. * aktprocdef renamed to current_procdef
  1387. * procinfo renamed to current_procinfo
  1388. * procinfo will now be stored in current_module so it can be
  1389. cleaned up properly
  1390. * gen_main_procsym changed to create_main_proc and release_main_proc
  1391. to also generate a tprocinfo structure
  1392. * fixed unit implicit initfinal
  1393. Revision 1.42 2003/03/16 20:45:45 mazen
  1394. * fixing an LD operation without refernce in loading address parameters
  1395. Revision 1.41 2003/03/10 21:59:54 mazen
  1396. * fixing index overflow in handling new registers arrays.
  1397. Revision 1.40 2003/02/25 21:41:44 mazen
  1398. * code re-aligned 2 spaces
  1399. Revision 1.39 2003/02/19 22:00:16 daniel
  1400. * Code generator converted to new register notation
  1401. - Horribily outdated todo.txt removed
  1402. Revision 1.38 2003/02/18 22:00:20 mazen
  1403. * asm condition generation modified by TAiCpu.SetCondition
  1404. Revision 1.37 2003/02/05 21:48:34 mazen
  1405. * fixing run time errors related to unimplemented abstract methods in CG
  1406. + giving empty emplementations for some RTL functions
  1407. Revision 1.36 2003/01/22 22:30:03 mazen
  1408. - internal errors rmoved from a_loar_reg_reg when reg sizes differs from 32
  1409. Revision 1.35 2003/01/20 22:21:36 mazen
  1410. * many stuff related to RTL fixed
  1411. Revision 1.34 2003/01/08 18:43:58 daniel
  1412. * Tregister changed into a record
  1413. Revision 1.33 2003/01/07 22:03:40 mazen
  1414. * adding unequaln node support to sparc compiler
  1415. Revision 1.32 2003/01/06 22:51:47 mazen
  1416. * fixing bugs related to load_reg_ref
  1417. Revision 1.31 2003/01/05 21:32:35 mazen
  1418. * fixing several bugs compiling the RTL
  1419. Revision 1.30 2003/01/05 13:36:53 florian
  1420. * x86-64 compiles
  1421. + very basic support for float128 type (x86-64 only)
  1422. Revision 1.29 2002/12/25 20:59:49 mazen
  1423. - many emitXXX removed from cga.pas in order to remove that file.
  1424. Revision 1.28 2002/12/22 19:26:31 mazen
  1425. * many internal errors related to unimplemented nodes are fixed
  1426. Revision 1.27 2002/12/21 23:21:47 mazen
  1427. + added support for the shift nodes
  1428. + added debug output on screen with -an command line option
  1429. Revision 1.26 2002/11/25 19:21:49 mazen
  1430. * fixed support of nSparcInline
  1431. Revision 1.25 2002/11/25 17:43:28 peter
  1432. * splitted defbase in defutil,symutil,defcmp
  1433. * merged isconvertable and is_equal into compare_defs(_ext)
  1434. * made operator search faster by walking the list only once
  1435. Revision 1.24 2002/11/17 17:49:09 mazen
  1436. + 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
  1437. Revision 1.23 2002/11/10 19:07:46 mazen
  1438. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  1439. Revision 1.22 2002/11/06 11:31:24 mazen
  1440. * op_reg_reg_reg don't need any more a TOpSize parameter
  1441. Revision 1.21 2002/11/05 16:15:00 mazen
  1442. *** empty log message ***
  1443. Revision 1.20 2002/11/03 20:22:40 mazen
  1444. * parameter handling updated
  1445. Revision 1.19 2002/10/28 20:59:17 mazen
  1446. * TOpSize values changed S_L --> S_SW
  1447. Revision 1.18 2002/10/22 13:43:01 mazen
  1448. - cga.pas redueced to an empty unit
  1449. Revision 1.17 2002/10/20 19:01:38 mazen
  1450. + op_raddr_reg and op_caddr_reg added to fix functions prologue
  1451. Revision 1.16 2002/10/13 21:46:07 mazen
  1452. * assembler output format fixed
  1453. Revision 1.15 2002/10/11 13:35:14 mazen
  1454. *** empty log message ***
  1455. Revision 1.14 2002/10/10 19:57:51 mazen
  1456. * Just to update repsitory
  1457. Revision 1.13 2002/10/10 15:10:39 mazen
  1458. * Internal error fixed, but usually i386 parameter model used
  1459. Revision 1.12 2002/10/08 17:17:03 mazen
  1460. *** empty log message ***
  1461. Revision 1.11 2002/10/07 20:33:04 mazen
  1462. word alignement modified in g_stack_frame
  1463. Revision 1.10 2002/10/04 21:57:42 mazen
  1464. * register allocation for parameters now done in cpupara, but InternalError(200109223) in cgcpu.pas:1053 is still not fixed du to location_force problem in ncgutils.pas:419
  1465. Revision 1.9 2002/10/02 22:20:28 mazen
  1466. + out registers allocator for the first 6 scalar parameters which must be passed into %o0..%o5
  1467. Revision 1.8 2002/10/01 21:35:58 mazen
  1468. + procedures exiting prologue added and stack frame now restored in the delay slot of the return (JMPL) instruction
  1469. Revision 1.7 2002/10/01 21:06:29 mazen
  1470. attinst.inc --> strinst.inc
  1471. Revision 1.6 2002/10/01 17:41:50 florian
  1472. * fixed log and id
  1473. }