cgcpu.pas 50 KB

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