cgcpu.pas 58 KB

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