cgcpu.pas 51 KB

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