cgcpu.pas 56 KB

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