cgcpu.pas 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961
  1. {
  2. Copyright (c) 1998-2012 by Florian Klaempfl and David Zhang
  3. This unit implements the code generator for MIPS
  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. }
  17. unit cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype, parabase,
  22. cgbase, cgutils, cgobj,
  23. {$ifndef mips64}
  24. cg64f32,
  25. {$endif mips64}
  26. cpupara,
  27. aasmbase, aasmtai, aasmcpu, aasmdata,
  28. cpubase, cpuinfo,
  29. node, symconst, SymType, symdef,
  30. rgcpu;
  31. type
  32. TCGMIPS = class(tcg)
  33. public
  34. procedure init_register_allocators; override;
  35. procedure done_register_allocators; override;
  36. /// { needed by cg64 }
  37. procedure make_simple_ref(list: tasmlist; var ref: treference);
  38. procedure handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  39. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  40. procedure overflowcheck_internal(list: TAsmList; arg1, arg2: TRegister);
  41. { parameter }
  42. procedure a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override;
  43. procedure a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); override;
  44. procedure a_call_name(list: tasmlist; const s: string; weak : boolean); override;
  45. procedure a_call_reg(list: tasmlist; Reg: TRegister); override;
  46. procedure a_call_sym_pic(list: tasmlist; sym: tasmsymbol);
  47. { General purpose instructions }
  48. procedure a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister); override;
  49. procedure a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  50. procedure a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  51. procedure a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  52. procedure a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  53. procedure a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  54. { move instructions }
  55. procedure a_load_const_reg(list: tasmlist; size: tcgsize; a: tcgint; reg: tregister); override;
  56. procedure a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference); override;
  57. procedure a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCgSize; reg: TRegister; const ref: TReference); override;
  58. procedure a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister); override;
  59. procedure a_load_reg_reg(list: tasmlist; FromSize, ToSize: TCgSize; reg1, reg2: tregister); override;
  60. procedure a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister); override;
  61. { fpu move instructions }
  62. procedure a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  63. procedure a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister); override;
  64. procedure a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference); override;
  65. { comparison operations }
  66. procedure a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  67. procedure a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  68. procedure a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel); override;
  69. procedure g_flags2reg(list: tasmlist; size: TCgSize; const f: TResFlags; reg: tregister); override;
  70. procedure a_jmp_always(List: tasmlist; l: TAsmLabel); override;
  71. procedure a_jmp_name(list: tasmlist; const s: string); override;
  72. procedure a_mul_reg_reg_pair(list: tasmlist; size: tcgsize; src1,src2,dstlo,dsthi: tregister); override;
  73. procedure g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); override;
  74. procedure g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation); override;
  75. procedure g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean); override;
  76. procedure g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean); override;
  77. procedure g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  78. procedure g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  79. procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  80. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  81. procedure g_profilecode(list: TAsmList);override;
  82. end;
  83. {$ifndef mips64}
  84. TCg64MPSel = class(tcg64f32)
  85. public
  86. procedure a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference); override;
  87. procedure a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64); override;
  88. procedure a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara); override;
  89. procedure a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64); override;
  90. procedure a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64); override;
  91. procedure a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64); override;
  92. procedure a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64); override;
  93. procedure a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  94. procedure a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  95. end;
  96. {$endif mips64}
  97. procedure create_codegen;
  98. const
  99. TOpCmp2AsmCond : array[topcmp] of TAsmCond=(C_NONE,
  100. C_EQ,C_GT,C_LT,C_GE,C_LE,C_NE,C_LEU,C_LTU,C_GEU,C_GTU
  101. );
  102. implementation
  103. uses
  104. globals, verbose, systems, cutils,
  105. paramgr, fmodule,
  106. symtable, symsym,
  107. tgobj,
  108. procinfo, cpupi;
  109. const
  110. TOpcg2AsmOp: array[TOpCg] of TAsmOp = (
  111. A_NONE,A_NONE,A_ADDU,A_AND,A_NONE,A_NONE,A_MULT,A_MULTU,A_NONE,A_NONE,
  112. A_OR,A_SRAV,A_SLLV,A_SRLV,A_SUBU,A_XOR,A_NONE,A_NONE
  113. );
  114. procedure TCGMIPS.make_simple_ref(list: tasmlist; var ref: treference);
  115. var
  116. tmpreg, tmpreg1: tregister;
  117. tmpref: treference;
  118. base_replaced: boolean;
  119. begin
  120. { Enforce some discipline for callers:
  121. - gp is always implicit
  122. - reference is processed only once }
  123. if (ref.base=NR_GP) or (ref.index=NR_GP) then
  124. InternalError(2013022801);
  125. if (ref.refaddr<>addr_no) then
  126. InternalError(2013022802);
  127. { fixup base/index, if both are present then add them together }
  128. base_replaced:=false;
  129. tmpreg:=ref.base;
  130. if (tmpreg=NR_NO) then
  131. tmpreg:=ref.index
  132. else if (ref.index<>NR_NO) then
  133. begin
  134. tmpreg:=getintregister(list,OS_ADDR);
  135. list.concat(taicpu.op_reg_reg_reg(A_ADDU,tmpreg,ref.base,ref.index));
  136. base_replaced:=true;
  137. end;
  138. ref.base:=tmpreg;
  139. ref.index:=NR_NO;
  140. if (ref.symbol=nil) and
  141. (ref.offset>=simm16lo) and
  142. (ref.offset<=simm16hi-sizeof(pint)) then
  143. exit;
  144. { Symbol present or offset > 16bits }
  145. if assigned(ref.symbol) then
  146. begin
  147. ref.base:=getintregister(list,OS_ADDR);
  148. reference_reset_symbol(tmpref,ref.symbol,ref.offset,ref.alignment,ref.volatility);
  149. if (cs_create_pic in current_settings.moduleswitches) then
  150. begin
  151. if not (pi_needs_got in current_procinfo.flags) then
  152. InternalError(2013060102);
  153. { For PIC global symbols offset must be handled separately.
  154. Otherwise (non-PIC or local symbols) offset can be encoded
  155. into relocation even if exceeds 16 bits. }
  156. if (ref.symbol.bind<>AB_LOCAL) then
  157. tmpref.offset:=0;
  158. tmpref.refaddr:=addr_pic;
  159. tmpref.base:=NR_GP;
  160. list.concat(taicpu.op_reg_ref(A_LW,ref.base,tmpref));
  161. end
  162. else
  163. begin
  164. tmpref.refaddr:=addr_high;
  165. list.concat(taicpu.op_reg_ref(A_LUI,ref.base,tmpref));
  166. end;
  167. { Add original base/index, if any. }
  168. if (tmpreg<>NR_NO) then
  169. list.concat(taicpu.op_reg_reg_reg(A_ADDU,ref.base,tmpreg,ref.base));
  170. if (ref.symbol.bind=AB_LOCAL) or
  171. not (cs_create_pic in current_settings.moduleswitches) then
  172. begin
  173. ref.refaddr:=addr_low;
  174. exit;
  175. end;
  176. { PIC global symbol }
  177. ref.symbol:=nil;
  178. if (ref.offset>=simm16lo) and
  179. (ref.offset<=simm16hi-sizeof(pint)) then
  180. exit;
  181. { fallthrough to the case of large offset }
  182. end;
  183. tmpreg1:=getintregister(list,OS_INT);
  184. a_load_const_reg(list,OS_INT,ref.offset,tmpreg1);
  185. if (ref.base=NR_NO) then
  186. ref.base:=tmpreg1 { offset alone, weird but possible }
  187. else
  188. begin
  189. tmpreg:=ref.base;
  190. if (not base_replaced) then
  191. ref.base:=getintregister(list,OS_ADDR);
  192. list.concat(taicpu.op_reg_reg_reg(A_ADDU,ref.base,tmpreg,tmpreg1))
  193. end;
  194. ref.offset:=0;
  195. end;
  196. procedure TCGMIPS.handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  197. var
  198. tmpreg: tregister;
  199. op2: Tasmop;
  200. negate: boolean;
  201. begin
  202. case op of
  203. A_ADD,A_SUB:
  204. op2:=A_ADDI;
  205. A_ADDU,A_SUBU:
  206. op2:=A_ADDIU;
  207. else
  208. InternalError(2013052001);
  209. end;
  210. negate:=op in [A_SUB,A_SUBU];
  211. { subtraction is actually addition of negated value, so possible range is
  212. off by one (-32767..32768) }
  213. if (a < simm16lo+ord(negate)) or
  214. (a > simm16hi+ord(negate)) then
  215. begin
  216. tmpreg := GetIntRegister(list, OS_INT);
  217. a_load_const_reg(list, OS_INT, a, tmpreg);
  218. list.concat(taicpu.op_reg_reg_reg(op, dst, src, tmpreg));
  219. end
  220. else
  221. begin
  222. if negate then
  223. a:=-a;
  224. list.concat(taicpu.op_reg_reg_const(op2, dst, src, a));
  225. end;
  226. end;
  227. {****************************************************************************
  228. Assembler code
  229. ****************************************************************************}
  230. procedure TCGMIPS.init_register_allocators;
  231. begin
  232. inherited init_register_allocators;
  233. { Keep RS_R25, i.e. $t9 for PIC call }
  234. if (cs_create_pic in current_settings.moduleswitches) and assigned(current_procinfo) and
  235. (pi_needs_got in current_procinfo.flags) then
  236. begin
  237. current_procinfo.got := NR_GP;
  238. rg[R_INTREGISTER] := Trgintcpu.Create(R_INTREGISTER, R_SUBD,
  239. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  240. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  241. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  242. first_int_imreg, []);
  243. end
  244. else
  245. rg[R_INTREGISTER] := trgintcpu.Create(R_INTREGISTER, R_SUBD,
  246. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  247. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  248. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  249. first_int_imreg, []);
  250. {
  251. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  252. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
  253. RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,
  254. RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,
  255. RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],
  256. first_fpu_imreg, []);
  257. }
  258. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  259. [RS_F0,RS_F2,RS_F4,RS_F6, RS_F8,RS_F10,RS_F12,RS_F14,
  260. RS_F16,RS_F18,RS_F20,RS_F22, RS_F24,RS_F26,RS_F28,RS_F30],
  261. first_fpu_imreg, []);
  262. end;
  263. procedure TCGMIPS.done_register_allocators;
  264. begin
  265. rg[R_INTREGISTER].Free;
  266. rg[R_FPUREGISTER].Free;
  267. inherited done_register_allocators;
  268. end;
  269. procedure TCGMIPS.a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara);
  270. var
  271. href, href2: treference;
  272. hloc: pcgparalocation;
  273. begin
  274. { TODO: inherited cannot deal with individual locations for each of OS_32 registers.
  275. Must change parameter management to allocate a single 64-bit register pair,
  276. then this method can be removed. }
  277. href := ref;
  278. hloc := paraloc.location;
  279. while assigned(hloc) do
  280. begin
  281. paramanager.allocparaloc(list,hloc);
  282. case hloc^.loc of
  283. LOC_REGISTER:
  284. a_load_ref_reg(list, hloc^.size, hloc^.size, href, hloc^.Register);
  285. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  286. a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  287. LOC_REFERENCE:
  288. begin
  289. paraloc.check_simple_location;
  290. reference_reset_base(href2,paraloc.location^.reference.index,paraloc.location^.reference.offset,ctempposinvalid,paraloc.alignment,[]);
  291. { concatcopy should choose the best way to copy the data }
  292. g_concatcopy(list,ref,href2,tcgsize2size[size]);
  293. end;
  294. else
  295. internalerror(200408241);
  296. end;
  297. Inc(href.offset, tcgsize2size[hloc^.size]);
  298. hloc := hloc^.Next;
  299. end;
  300. end;
  301. procedure TCGMIPS.a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara);
  302. var
  303. href: treference;
  304. begin
  305. if paraloc.Location^.next=nil then
  306. begin
  307. inherited a_loadfpu_reg_cgpara(list,size,r,paraloc);
  308. exit;
  309. end;
  310. tg.GetTemp(list, TCGSize2Size[size], TCGSize2Size[size], tt_normal, href);
  311. a_loadfpu_reg_ref(list, size, size, r, href);
  312. a_loadfpu_ref_cgpara(list, size, href, paraloc);
  313. tg.Ungettemp(list, href);
  314. end;
  315. procedure TCGMIPS.a_call_sym_pic(list: tasmlist; sym: tasmsymbol);
  316. var
  317. href: treference;
  318. begin
  319. reference_reset_symbol(href,sym,0,sizeof(aint),[]);
  320. if (sym.bind=AB_LOCAL) then
  321. href.refaddr:=addr_pic
  322. else
  323. href.refaddr:=addr_pic_call16;
  324. href.base:=NR_GP;
  325. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  326. if (sym.bind=AB_LOCAL) then
  327. begin
  328. href.refaddr:=addr_low;
  329. href.base:=NR_NO;
  330. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  331. end;
  332. list.concat(taicpu.op_reg(A_JALR,NR_PIC_FUNC));
  333. { Delay slot }
  334. list.concat(taicpu.op_none(A_NOP));
  335. { Restore GP if in PIC mode }
  336. if (cs_create_pic in current_settings.moduleswitches) then
  337. begin
  338. if tcpuprocinfo(current_procinfo).save_gp_ref.offset=0 then
  339. InternalError(2013071001);
  340. list.concat(taicpu.op_reg_ref(A_LW,NR_GP,tcpuprocinfo(current_procinfo).save_gp_ref));
  341. end;
  342. end;
  343. procedure TCGMIPS.a_call_name(list: tasmlist; const s: string; weak: boolean);
  344. var
  345. sym: tasmsymbol;
  346. begin
  347. if assigned(current_procinfo) and
  348. not (pi_do_call in current_procinfo.flags) then
  349. InternalError(2013022101);
  350. if weak then
  351. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
  352. else
  353. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  354. if (cs_create_pic in current_settings.moduleswitches) then
  355. a_call_sym_pic(list,sym)
  356. else
  357. begin
  358. list.concat(taicpu.op_sym(A_JAL,sym));
  359. { Delay slot }
  360. list.concat(taicpu.op_none(A_NOP));
  361. end;
  362. end;
  363. procedure TCGMIPS.a_call_reg(list: tasmlist; Reg: TRegister);
  364. begin
  365. if assigned(current_procinfo) and
  366. not (pi_do_call in current_procinfo.flags) then
  367. InternalError(2013022102);
  368. if (Reg <> NR_PIC_FUNC) then
  369. list.concat(taicpu.op_reg_reg(A_MOVE,NR_PIC_FUNC,reg));
  370. list.concat(taicpu.op_reg(A_JALR,NR_PIC_FUNC));
  371. { Delay slot }
  372. list.concat(taicpu.op_none(A_NOP));
  373. { Restore GP if in PIC mode }
  374. if (cs_create_pic in current_settings.moduleswitches) then
  375. begin
  376. if tcpuprocinfo(current_procinfo).save_gp_ref.offset=0 then
  377. InternalError(2013071002);
  378. list.concat(taicpu.op_reg_ref(A_LW,NR_GP,tcpuprocinfo(current_procinfo).save_gp_ref));
  379. end;
  380. end;
  381. {********************** load instructions ********************}
  382. procedure TCGMIPS.a_load_const_reg(list: tasmlist; size: TCGSize; a: tcgint; reg: TRegister);
  383. begin
  384. if (a = 0) then
  385. a_load_reg_reg(list, OS_INT, OS_INT, NR_R0, reg)
  386. else if (a >= simm16lo) and (a <= simm16hi) then
  387. list.concat(taicpu.op_reg_reg_const(A_ADDIU, reg, NR_R0, a))
  388. else if (a>=0) and (a <= 65535) then
  389. list.concat(taicpu.op_reg_reg_const(A_ORI, reg, NR_R0, a))
  390. else
  391. begin
  392. list.concat(taicpu.op_reg_const(A_LUI, reg, aint(a) shr 16));
  393. if (a and aint($FFFF))<>0 then
  394. list.concat(taicpu.op_reg_reg_const(A_ORI,reg,reg,a and aint($FFFF)));
  395. end;
  396. end;
  397. procedure TCGMIPS.a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference);
  398. begin
  399. if a = 0 then
  400. a_load_reg_ref(list, size, size, NR_R0, ref)
  401. else
  402. inherited a_load_const_ref(list, size, a, ref);
  403. end;
  404. procedure TCGMIPS.a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCGSize; reg: tregister; const Ref: TReference);
  405. var
  406. op: tasmop;
  407. href: treference;
  408. begin
  409. if (TCGSize2Size[fromsize] < TCGSize2Size[tosize]) then
  410. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  411. if (ref.alignment<>0) and
  412. (ref.alignment<tcgsize2size[tosize]) then
  413. begin
  414. a_load_reg_ref_unaligned(list,FromSize,ToSize,reg,ref);
  415. exit;
  416. end;
  417. case tosize of
  418. OS_8,
  419. OS_S8:
  420. Op := A_SB;
  421. OS_16,
  422. OS_S16:
  423. Op := A_SH;
  424. OS_32,
  425. OS_S32:
  426. Op := A_SW;
  427. else
  428. InternalError(2002122100);
  429. end;
  430. href:=ref;
  431. make_simple_ref(list,href);
  432. list.concat(taicpu.op_reg_ref(op,reg,href));
  433. end;
  434. procedure TCGMIPS.a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister);
  435. var
  436. op: tasmop;
  437. href: treference;
  438. begin
  439. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  440. fromsize := tosize;
  441. if (ref.alignment<>0) and
  442. (ref.alignment<tcgsize2size[fromsize]) then
  443. begin
  444. a_load_ref_reg_unaligned(list,FromSize,ToSize,ref,reg);
  445. exit;
  446. end;
  447. case fromsize of
  448. OS_S8:
  449. Op := A_LB;{Load Signed Byte}
  450. OS_8:
  451. Op := A_LBU;{Load Unsigned Byte}
  452. OS_S16:
  453. Op := A_LH;{Load Signed Halfword}
  454. OS_16:
  455. Op := A_LHU;{Load Unsigned Halfword}
  456. OS_S32:
  457. Op := A_LW;{Load Word}
  458. OS_32:
  459. Op := A_LW;//A_LWU;{Load Unsigned Word}
  460. OS_S64,
  461. OS_64:
  462. Op := A_LD;{Load a Long Word}
  463. else
  464. InternalError(2002122101);
  465. end;
  466. href:=ref;
  467. make_simple_ref(list,href);
  468. list.concat(taicpu.op_reg_ref(op,reg,href));
  469. if (fromsize=OS_S8) and (tosize=OS_16) then
  470. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  471. end;
  472. procedure TCGMIPS.a_load_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  473. var
  474. instr: taicpu;
  475. done: boolean;
  476. begin
  477. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  478. (
  479. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and (tosize <> fromsize)
  480. ) or ((fromsize = OS_S8) and
  481. (tosize = OS_16)) then
  482. begin
  483. done:=true;
  484. case tosize of
  485. OS_8:
  486. list.concat(taicpu.op_reg_reg_const(A_ANDI, reg2, reg1, $ff));
  487. OS_16:
  488. list.concat(taicpu.op_reg_reg_const(A_ANDI, reg2, reg1, $ffff));
  489. OS_32,
  490. OS_S32:
  491. done:=false;
  492. OS_S8:
  493. begin
  494. if (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]) then
  495. list.concat(taicpu.op_reg_reg(A_SEB,reg2,reg1))
  496. else
  497. begin
  498. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 24));
  499. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 24));
  500. end;
  501. end;
  502. OS_S16:
  503. begin
  504. if (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]) then
  505. list.concat(taicpu.op_reg_reg(A_SEH,reg2,reg1))
  506. else
  507. begin
  508. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 16));
  509. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 16));
  510. end;
  511. end;
  512. else
  513. internalerror(2002090901);
  514. end;
  515. end
  516. else
  517. done:=false;
  518. if (not done) and (reg1 <> reg2) then
  519. begin
  520. { same size, only a register mov required }
  521. instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1);
  522. list.Concat(instr);
  523. { Notify the register allocator that we have written a move instruction so
  524. it can try to eliminate it. }
  525. add_move_instruction(instr);
  526. end;
  527. end;
  528. procedure TCGMIPS.a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister);
  529. var
  530. href: treference;
  531. hreg: tregister;
  532. begin
  533. { Enforce some discipline for callers:
  534. - reference must be a "raw" one and not use gp }
  535. if (ref.base=NR_GP) or (ref.index=NR_GP) then
  536. InternalError(2013022803);
  537. if (ref.refaddr<>addr_no) then
  538. InternalError(2013022804);
  539. if (ref.base=NR_NO) and (ref.index<>NR_NO) then
  540. InternalError(200306171);
  541. if (ref.symbol=nil) then
  542. begin
  543. if (ref.base<>NR_NO) then
  544. begin
  545. if (ref.offset<simm16lo) or (ref.offset>simm16hi) then
  546. begin
  547. hreg:=getintregister(list,OS_INT);
  548. a_load_const_reg(list,OS_INT,ref.offset,hreg);
  549. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,ref.base,hreg));
  550. end
  551. else if (ref.offset<>0) then
  552. list.concat(taicpu.op_reg_reg_const(A_ADDIU,r,ref.base,ref.offset))
  553. else
  554. a_load_reg_reg(list,OS_INT,OS_INT,ref.base,r); { emit optimizable move }
  555. if (ref.index<>NR_NO) then
  556. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.index));
  557. end
  558. else
  559. a_load_const_reg(list,OS_INT,ref.offset,r);
  560. exit;
  561. end;
  562. reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
  563. if (cs_create_pic in current_settings.moduleswitches) then
  564. begin
  565. if not (pi_needs_got in current_procinfo.flags) then
  566. InternalError(2013060104);
  567. { For PIC global symbols offset must be handled separately.
  568. Otherwise (non-PIC or local symbols) offset can be encoded
  569. into relocation even if exceeds 16 bits. }
  570. if (href.symbol.bind<>AB_LOCAL) then
  571. href.offset:=0;
  572. href.refaddr:=addr_pic;
  573. href.base:=NR_GP;
  574. list.concat(taicpu.op_reg_ref(A_LW,r,href));
  575. end
  576. else
  577. begin
  578. href.refaddr:=addr_high;
  579. list.concat(taicpu.op_reg_ref(A_LUI,r,href));
  580. end;
  581. { Add original base/index, if any. }
  582. if (ref.base<>NR_NO) then
  583. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.base));
  584. if (ref.index<>NR_NO) then
  585. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,ref.index));
  586. { add low part if necessary }
  587. if (ref.symbol.bind=AB_LOCAL) or
  588. not (cs_create_pic in current_settings.moduleswitches) then
  589. begin
  590. href.refaddr:=addr_low;
  591. href.base:=NR_NO;
  592. list.concat(taicpu.op_reg_reg_ref(A_ADDIU,r,r,href));
  593. exit;
  594. end;
  595. if (ref.offset<simm16lo) or (ref.offset>simm16hi) then
  596. begin
  597. hreg:=getintregister(list,OS_INT);
  598. a_load_const_reg(list,OS_INT,ref.offset,hreg);
  599. list.concat(taicpu.op_reg_reg_reg(A_ADDU,r,r,hreg));
  600. end
  601. else if (ref.offset<>0) then
  602. list.concat(taicpu.op_reg_reg_const(A_ADDIU,r,r,ref.offset));
  603. end;
  604. procedure TCGMIPS.a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  605. const
  606. FpuMovInstr: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  607. ((A_MOV_S, A_CVT_D_S),(A_CVT_S_D,A_MOV_D));
  608. var
  609. instr: taicpu;
  610. begin
  611. if (reg1 <> reg2) or (fromsize<>tosize) then
  612. begin
  613. instr := taicpu.op_reg_reg(fpumovinstr[fromsize,tosize], reg2, reg1);
  614. list.Concat(instr);
  615. { Notify the register allocator that we have written a move instruction so
  616. it can try to eliminate it. }
  617. if (fromsize=tosize) then
  618. add_move_instruction(instr);
  619. end;
  620. end;
  621. procedure TCGMIPS.a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister);
  622. var
  623. href: TReference;
  624. begin
  625. href:=ref;
  626. make_simple_ref(list,href);
  627. case fromsize of
  628. OS_F32:
  629. list.concat(taicpu.op_reg_ref(A_LWC1,reg,href));
  630. OS_F64:
  631. list.concat(taicpu.op_reg_ref(A_LDC1,reg,href));
  632. else
  633. InternalError(2007042701);
  634. end;
  635. if tosize<>fromsize then
  636. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  637. end;
  638. procedure TCGMIPS.a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference);
  639. var
  640. href: TReference;
  641. begin
  642. if tosize<>fromsize then
  643. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  644. href:=ref;
  645. make_simple_ref(list,href);
  646. case tosize of
  647. OS_F32:
  648. list.concat(taicpu.op_reg_ref(A_SWC1,reg,href));
  649. OS_F64:
  650. list.concat(taicpu.op_reg_ref(A_SDC1,reg,href));
  651. else
  652. InternalError(2007042702);
  653. end;
  654. end;
  655. procedure TCGMIPS.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  656. const
  657. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  658. begin
  659. if (op in overflowops) and
  660. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  661. a_load_reg_reg(list,OS_32,size,dst,dst);
  662. end;
  663. procedure TCGMIPS.overflowcheck_internal(list: tasmlist; arg1, arg2: tregister);
  664. var
  665. carry, hreg: tregister;
  666. begin
  667. if (arg1=arg2) then
  668. InternalError(2013050501);
  669. carry:=GetIntRegister(list,OS_INT);
  670. hreg:=GetIntRegister(list,OS_INT);
  671. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,arg1,arg2));
  672. { if carry<>0, this will cause hardware overflow interrupt }
  673. a_load_const_reg(list,OS_INT,$80000000,hreg);
  674. list.concat(taicpu.op_reg_reg_reg(A_SUB,hreg,hreg,carry));
  675. end;
  676. const
  677. ops_add: array[boolean] of TAsmOp = (A_ADDU, A_ADD);
  678. ops_sub: array[boolean] of TAsmOp = (A_SUBU, A_SUB);
  679. ops_slt: array[boolean] of TAsmOp = (A_SLTU, A_SLT);
  680. ops_slti: array[boolean] of TAsmOp = (A_SLTIU, A_SLTI);
  681. ops_and: array[boolean] of TAsmOp = (A_AND, A_ANDI);
  682. ops_or: array[boolean] of TAsmOp = (A_OR, A_ORI);
  683. ops_xor: array[boolean] of TasmOp = (A_XOR, A_XORI);
  684. procedure TCGMIPS.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister);
  685. begin
  686. optimize_op_const(size,op,a);
  687. case op of
  688. OP_NONE:
  689. exit;
  690. OP_MOVE:
  691. a_load_const_reg(list,size,a,reg);
  692. OP_NEG,OP_NOT:
  693. internalerror(200306011);
  694. else
  695. a_op_const_reg_reg(list,op,size,a,reg,reg);
  696. end;
  697. end;
  698. procedure TCGMIPS.a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  699. begin
  700. case Op of
  701. OP_NEG:
  702. list.concat(taicpu.op_reg_reg_reg(A_SUBU, dst, NR_R0, src));
  703. OP_NOT:
  704. list.concat(taicpu.op_reg_reg_reg(A_NOR, dst, NR_R0, src));
  705. OP_IMUL,OP_MUL:
  706. begin
  707. list.concat(taicpu.op_reg_reg(TOpcg2AsmOp[op], dst, src));
  708. list.concat(taicpu.op_reg(A_MFLO, dst));
  709. end;
  710. else
  711. a_op_reg_reg_reg(list, op, size, src, dst, dst);
  712. exit;
  713. end;
  714. maybeadjustresult(list,op,size,dst);
  715. end;
  716. procedure TCGMIPS.a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  717. var
  718. l: TLocation;
  719. begin
  720. a_op_const_reg_reg_checkoverflow(list, op, size, a, src, dst, false, l);
  721. end;
  722. procedure TCGMIPS.a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  723. begin
  724. if (TOpcg2AsmOp[op]=A_NONE) then
  725. InternalError(2013070305);
  726. if (op=OP_SAR) then
  727. begin
  728. if (size in [OS_S8,OS_S16]) then
  729. begin
  730. { Sign-extend before shiting }
  731. list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src2, 32-(tcgsize2size[size]*8)));
  732. list.concat(taicpu.op_reg_reg_const(A_SRA, dst, dst, 32-(tcgsize2size[size]*8)));
  733. src2:=dst;
  734. end
  735. else if not (size in [OS_32,OS_S32]) then
  736. InternalError(2013070306);
  737. end;
  738. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  739. maybeadjustresult(list,op,size,dst);
  740. end;
  741. procedure TCGMIPS.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  742. var
  743. signed,immed: boolean;
  744. hreg: TRegister;
  745. asmop: TAsmOp;
  746. begin
  747. a:=aint(a);
  748. ovloc.loc := LOC_VOID;
  749. optimize_op_const(size,op,a);
  750. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  751. if (setflags and (not signed) and (src=dst) and (op in [OP_ADD,OP_SUB])) then
  752. hreg:=GetIntRegister(list,OS_INT)
  753. else
  754. hreg:=dst;
  755. case op of
  756. OP_NONE:
  757. a_load_reg_reg(list,size,size,src,dst);
  758. OP_MOVE:
  759. a_load_const_reg(list,size,a,dst);
  760. OP_ADD:
  761. begin
  762. handle_reg_const_reg(list,ops_add[setflags and signed],src,a,hreg);
  763. if setflags and (not signed) then
  764. overflowcheck_internal(list,hreg,src);
  765. { does nothing if hreg=dst }
  766. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  767. end;
  768. OP_SUB:
  769. begin
  770. handle_reg_const_reg(list,ops_sub[setflags and signed],src,a,hreg);
  771. if setflags and (not signed) then
  772. overflowcheck_internal(list,src,hreg);
  773. a_load_reg_reg(list,OS_INT,OS_INT,hreg,dst);
  774. end;
  775. OP_MUL,OP_IMUL:
  776. begin
  777. hreg:=GetIntRegister(list,OS_INT);
  778. a_load_const_reg(list,OS_INT,a,hreg);
  779. a_op_reg_reg_reg_checkoverflow(list,op,size,src,hreg,dst,setflags,ovloc);
  780. exit;
  781. end;
  782. OP_AND,OP_OR,OP_XOR:
  783. begin
  784. { logical operations zero-extend, not sign-extend, the immediate }
  785. immed:=(a>=0) and (a<=65535);
  786. case op of
  787. OP_AND: asmop:=ops_and[immed];
  788. OP_OR: asmop:=ops_or[immed];
  789. OP_XOR: asmop:=ops_xor[immed];
  790. else
  791. InternalError(2013050401);
  792. end;
  793. if immed then
  794. list.concat(taicpu.op_reg_reg_const(asmop,dst,src,a))
  795. else
  796. begin
  797. hreg:=GetIntRegister(list,OS_INT);
  798. a_load_const_reg(list,OS_INT,a,hreg);
  799. list.concat(taicpu.op_reg_reg_reg(asmop,dst,src,hreg));
  800. end;
  801. end;
  802. OP_SHL:
  803. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,a));
  804. OP_SHR:
  805. list.concat(taicpu.op_reg_reg_const(A_SRL,dst,src,a));
  806. OP_SAR:
  807. begin
  808. if (size in [OS_S8,OS_S16]) then
  809. begin
  810. list.concat(taicpu.op_reg_reg_const(A_SLL,dst,src,32-(tcgsize2size[size]*8)));
  811. inc(a,32-tcgsize2size[size]*8);
  812. src:=dst;
  813. end
  814. else if not (size in [OS_32,OS_S32]) then
  815. InternalError(2013070303);
  816. list.concat(taicpu.op_reg_reg_const(A_SRA,dst,src,a));
  817. end;
  818. else
  819. internalerror(2007012601);
  820. end;
  821. maybeadjustresult(list,op,size,dst);
  822. end;
  823. procedure TCGMIPS.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  824. var
  825. signed: boolean;
  826. hreg,hreg2: TRegister;
  827. hl: tasmlabel;
  828. begin
  829. ovloc.loc := LOC_VOID;
  830. signed:=(size in [OS_S8,OS_S16,OS_S32]);
  831. if (setflags and (not signed) and (src2=dst) and (op in [OP_ADD,OP_SUB])) then
  832. hreg:=GetIntRegister(list,OS_INT)
  833. else
  834. hreg:=dst;
  835. case op of
  836. OP_ADD:
  837. begin
  838. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], hreg, src2, src1));
  839. if setflags and (not signed) then
  840. overflowcheck_internal(list, hreg, src2);
  841. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  842. end;
  843. OP_SUB:
  844. begin
  845. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], hreg, src2, src1));
  846. if setflags and (not signed) then
  847. overflowcheck_internal(list, src2, hreg);
  848. a_load_reg_reg(list, OS_INT, OS_INT, hreg, dst);
  849. end;
  850. OP_MUL,OP_IMUL:
  851. begin
  852. if (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]) and
  853. (not setflags) then
  854. { NOTE: MUL is actually mips32r1 instruction; on older cores it is handled as macro }
  855. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1))
  856. else
  857. begin
  858. list.concat(taicpu.op_reg_reg(TOpCg2AsmOp[op], src2, src1));
  859. list.concat(taicpu.op_reg(A_MFLO, dst));
  860. if setflags then
  861. begin
  862. current_asmdata.getjumplabel(hl);
  863. hreg:=GetIntRegister(list,OS_INT);
  864. list.concat(taicpu.op_reg(A_MFHI,hreg));
  865. if (op=OP_IMUL) then
  866. begin
  867. hreg2:=GetIntRegister(list,OS_INT);
  868. list.concat(taicpu.op_reg_reg_const(A_SRA,hreg2,dst,31));
  869. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg2,hreg,hl);
  870. end
  871. else
  872. a_cmp_reg_reg_label(list,OS_INT,OC_EQ,hreg,NR_R0,hl);
  873. list.concat(taicpu.op_const(A_BREAK,6));
  874. a_label(list,hl);
  875. end;
  876. end;
  877. end;
  878. OP_AND,OP_OR,OP_XOR:
  879. begin
  880. list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op], dst, src2, src1));
  881. end;
  882. else
  883. internalerror(2007012602);
  884. end;
  885. maybeadjustresult(list,op,size,dst);
  886. end;
  887. {*************** compare instructructions ****************}
  888. procedure TCGMIPS.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  889. var
  890. tmpreg: tregister;
  891. begin
  892. if a = 0 then
  893. a_cmp_reg_reg_label(list,size,cmp_op,NR_R0,reg,l)
  894. else
  895. begin
  896. tmpreg := GetIntRegister(list,OS_INT);
  897. if (a>=simm16lo) and (a<=simm16hi) and
  898. (cmp_op in [OC_LT,OC_B,OC_GTE,OC_AE]) then
  899. begin
  900. list.concat(taicpu.op_reg_reg_const(ops_slti[cmp_op in [OC_LT,OC_GTE]],tmpreg,reg,a));
  901. if cmp_op in [OC_LT,OC_B] then
  902. a_cmp_reg_reg_label(list,size,OC_NE,NR_R0,tmpreg,l)
  903. else
  904. a_cmp_reg_reg_label(list,size,OC_EQ,NR_R0,tmpreg,l);
  905. end
  906. else
  907. begin
  908. a_load_const_reg(list,OS_INT,a,tmpreg);
  909. a_cmp_reg_reg_label(list, size, cmp_op, tmpreg, reg, l);
  910. end;
  911. end;
  912. end;
  913. const
  914. TOpCmp2AsmCond_z : array[OC_GT..OC_LTE] of TAsmCond=(
  915. C_GTZ,C_LTZ,C_GEZ,C_LEZ
  916. );
  917. TOpCmp2AsmCond_eqne: array[topcmp] of TAsmCond = (C_NONE,
  918. { eq gt lt gte lte ne }
  919. C_NONE, C_NE, C_NE, C_EQ, C_EQ, C_NONE,
  920. { be b ae a }
  921. C_EQ, C_NE, C_EQ, C_NE
  922. );
  923. procedure TCGMIPS.a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  924. var
  925. ai : Taicpu;
  926. op: TAsmOp;
  927. hreg: TRegister;
  928. begin
  929. if not (cmp_op in [OC_EQ,OC_NE]) then
  930. begin
  931. if ((reg1=NR_R0) or (reg2=NR_R0)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
  932. begin
  933. if (reg2=NR_R0) then
  934. begin
  935. ai:=taicpu.op_reg_sym(A_BC,reg1,l);
  936. ai.setcondition(TOpCmp2AsmCond_z[swap_opcmp(cmp_op)]);
  937. end
  938. else
  939. begin
  940. ai:=taicpu.op_reg_sym(A_BC,reg2,l);
  941. ai.setcondition(TOpCmp2AsmCond_z[cmp_op]);
  942. end;
  943. end
  944. else
  945. begin
  946. hreg:=GetIntRegister(list,OS_INT);
  947. op:=ops_slt[cmp_op in [OC_LT,OC_LTE,OC_GT,OC_GTE]];
  948. if (cmp_op in [OC_LTE,OC_GT,OC_BE,OC_A]) then { swap operands }
  949. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg1,reg2))
  950. else
  951. list.concat(taicpu.op_reg_reg_reg(op,hreg,reg2,reg1));
  952. if (TOpCmp2AsmCond_eqne[cmp_op]=C_NONE) then
  953. InternalError(2013051501);
  954. ai:=taicpu.op_reg_reg_sym(A_BC,hreg,NR_R0,l);
  955. ai.SetCondition(TOpCmp2AsmCond_eqne[cmp_op]);
  956. end;
  957. end
  958. else
  959. begin
  960. ai:=taicpu.op_reg_reg_sym(A_BC,reg2,reg1,l);
  961. ai.SetCondition(TOpCmp2AsmCond[cmp_op]);
  962. end;
  963. list.concat(ai);
  964. { Delay slot }
  965. list.Concat(TAiCpu.Op_none(A_NOP));
  966. end;
  967. procedure TCGMIPS.a_jmp_always(List: tasmlist; l: TAsmLabel);
  968. var
  969. ai : Taicpu;
  970. begin
  971. ai := taicpu.op_sym(A_BA, l);
  972. list.concat(ai);
  973. { Delay slot }
  974. list.Concat(TAiCpu.Op_none(A_NOP));
  975. end;
  976. procedure TCGMIPS.a_jmp_name(list: tasmlist; const s: string);
  977. begin
  978. List.Concat(TAiCpu.op_sym(A_BA, current_asmdata.RefAsmSymbol(s,AT_FUNCTION)));
  979. { Delay slot }
  980. list.Concat(TAiCpu.Op_none(A_NOP));
  981. end;
  982. procedure TCGMIPS.a_jmp_flags(list: tasmlist; const f: TResFlags; l: tasmlabel);
  983. var
  984. ai: taicpu;
  985. begin
  986. case f.reg1 of
  987. NR_FCC0..NR_FCC7:
  988. begin
  989. if (f.reg1=NR_FCC0) then
  990. ai:=taicpu.op_sym(A_BC,l)
  991. else
  992. ai:=taicpu.op_reg_sym(A_BC,f.reg1,l);
  993. list.concat(ai);
  994. { delay slot }
  995. list.concat(taicpu.op_none(A_NOP));
  996. case f.cond of
  997. OC_NE: ai.SetCondition(C_COP1TRUE);
  998. OC_EQ: ai.SetCondition(C_COP1FALSE);
  999. else
  1000. InternalError(2014082901);
  1001. end;
  1002. exit;
  1003. end;
  1004. else
  1005. ;
  1006. end;
  1007. if f.use_const then
  1008. a_cmp_const_reg_label(list,OS_INT,f.cond,f.value,f.reg1,l)
  1009. else
  1010. a_cmp_reg_reg_label(list,OS_INT,f.cond,f.reg2,f.reg1,l);
  1011. end;
  1012. procedure TCGMIPS.g_flags2reg(list: tasmlist; size: tcgsize; const f: tresflags; reg: tregister);
  1013. var
  1014. left,right: tregister;
  1015. unsigned: boolean;
  1016. hl: tasmlabel;
  1017. begin
  1018. case f.reg1 of
  1019. NR_FCC0..NR_FCC7:
  1020. begin
  1021. if (current_settings.cputype>=cpu_mips4) then
  1022. begin
  1023. a_load_const_reg(list,size,1,reg);
  1024. case f.cond of
  1025. OC_NE: list.concat(taicpu.op_reg_reg_reg(A_MOVF,reg,NR_R0,f.reg1));
  1026. OC_EQ: list.concat(taicpu.op_reg_reg_reg(A_MOVT,reg,NR_R0,f.reg1));
  1027. else
  1028. InternalError(2014082902);
  1029. end;
  1030. end
  1031. else
  1032. begin
  1033. { TODO: still possible to do branchless by extracting appropriate bit from FCSR? }
  1034. current_asmdata.getjumplabel(hl);
  1035. a_load_const_reg(list,size,1,reg);
  1036. a_jmp_flags(list,f,hl);
  1037. a_load_const_reg(list,size,0,reg);
  1038. a_label(list,hl);
  1039. end;
  1040. exit;
  1041. end;
  1042. else
  1043. ;
  1044. end;
  1045. if (f.cond in [OC_EQ,OC_NE]) then
  1046. begin
  1047. left:=reg;
  1048. if f.use_const and (f.value>=0) and (f.value<=65535) then
  1049. begin
  1050. if (f.value<>0) then
  1051. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,f.reg1,f.value))
  1052. else
  1053. left:=f.reg1;
  1054. end
  1055. else
  1056. begin
  1057. if f.use_const then
  1058. begin
  1059. right:=GetIntRegister(list,OS_INT);
  1060. a_load_const_reg(list,OS_INT,f.value,right);
  1061. end
  1062. else
  1063. right:=f.reg2;
  1064. list.concat(taicpu.op_reg_reg_reg(A_XOR,reg,f.reg1,right));
  1065. end;
  1066. if f.cond=OC_EQ then
  1067. list.concat(taicpu.op_reg_reg_const(A_SLTIU,reg,left,1))
  1068. else
  1069. list.concat(taicpu.op_reg_reg_reg(A_SLTU,reg,NR_R0,left));
  1070. end
  1071. else
  1072. begin
  1073. {
  1074. sle x,a,b --> slt x,b,a; xori x,x,1 immediate not possible (or must be at left)
  1075. sgt x,a,b --> slt x,b,a likewise
  1076. sge x,a,b --> slt x,a,b; xori x,x,1
  1077. slt x,a,b --> unchanged
  1078. }
  1079. unsigned:=f.cond in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  1080. if (f.cond in [OC_GTE,OC_LT,OC_B,OC_AE]) and
  1081. f.use_const and
  1082. (f.value>=simm16lo) and
  1083. (f.value<=simm16hi) then
  1084. list.Concat(taicpu.op_reg_reg_const(ops_slti[unsigned],reg,f.reg1,f.value))
  1085. else
  1086. begin
  1087. if f.use_const then
  1088. begin
  1089. if (f.value=0) then
  1090. right:=NR_R0
  1091. else
  1092. begin
  1093. right:=GetIntRegister(list,OS_INT);
  1094. a_load_const_reg(list,OS_INT,f.value,right);
  1095. end;
  1096. end
  1097. else
  1098. right:=f.reg2;
  1099. if (f.cond in [OC_LTE,OC_GT,OC_BE,OC_A]) then
  1100. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,right,f.reg1))
  1101. else
  1102. list.Concat(taicpu.op_reg_reg_reg(ops_slt[unsigned],reg,f.reg1,right));
  1103. end;
  1104. if (f.cond in [OC_LTE,OC_GTE,OC_BE,OC_AE]) then
  1105. list.Concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  1106. end;
  1107. end;
  1108. procedure TCGMIPS.a_mul_reg_reg_pair(list: tasmlist; size: tcgsize; src1,src2,dstlo,dsthi: tregister);
  1109. var
  1110. asmop: tasmop;
  1111. begin
  1112. case size of
  1113. OS_32: asmop:=A_MULTU;
  1114. OS_S32: asmop:=A_MULT;
  1115. else
  1116. InternalError(2014060802);
  1117. end;
  1118. list.concat(taicpu.op_reg_reg(asmop,src1,src2));
  1119. if (dstlo<>NR_NO) then
  1120. list.concat(taicpu.op_reg(A_MFLO,dstlo));
  1121. if (dsthi<>NR_NO) then
  1122. list.concat(taicpu.op_reg(A_MFHI,dsthi));
  1123. end;
  1124. procedure TCGMIPS.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef);
  1125. begin
  1126. // this is an empty procedure
  1127. end;
  1128. procedure TCGMIPS.g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation);
  1129. begin
  1130. // this is an empty procedure
  1131. end;
  1132. { *********** entry/exit code and address loading ************ }
  1133. procedure FixupOffsets(p:TObject;arg:pointer);
  1134. var
  1135. sym: tabstractnormalvarsym absolute p;
  1136. begin
  1137. if (tsym(p).typ=paravarsym) and
  1138. (sym.localloc.loc=LOC_REFERENCE) and
  1139. (sym.localloc.reference.base=NR_FRAME_POINTER_REG) then
  1140. begin
  1141. sym.localloc.reference.base:=NR_STACK_POINTER_REG;
  1142. Inc(sym.localloc.reference.offset,PLongint(arg)^);
  1143. end;
  1144. end;
  1145. procedure TCGMIPS.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean);
  1146. var
  1147. lastintoffset,lastfpuoffset,
  1148. nextoffset : aint;
  1149. i : longint;
  1150. ra_save,framesave : taicpu;
  1151. fmask,mask : dword;
  1152. saveregs : tcpuregisterset;
  1153. href: treference;
  1154. reg : Tsuperregister;
  1155. helplist : TAsmList;
  1156. largeoffs : boolean;
  1157. begin
  1158. list.concat(tai_directive.create(asd_ent,current_procinfo.procdef.mangledname));
  1159. if nostackframe then
  1160. begin
  1161. list.concat(taicpu.op_none(A_P_SET_NOMIPS16));
  1162. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1163. exit;
  1164. end;
  1165. helplist:=TAsmList.Create;
  1166. reference_reset(href,0,[]);
  1167. href.base:=NR_STACK_POINTER_REG;
  1168. fmask:=0;
  1169. nextoffset:=tcpuprocinfo(current_procinfo).floatregstart;
  1170. lastfpuoffset:=LocalSize;
  1171. for reg := RS_F0 to RS_F31 do { to check: what if F30 is double? }
  1172. begin
  1173. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1174. begin
  1175. fmask:=fmask or (longword(1) shl ord(reg));
  1176. href.offset:=nextoffset;
  1177. lastfpuoffset:=nextoffset;
  1178. helplist.concat(taicpu.op_reg_ref(A_SWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1179. inc(nextoffset,4);
  1180. { IEEE Double values are stored in floating point
  1181. register pairs f2X/f2X+1,
  1182. as the f2X+1 register is not correctly marked as used for now,
  1183. we simply assume it is also used if f2X is used
  1184. Should be fixed by a proper inclusion of f2X+1 into used_in_proc }
  1185. if (ord(reg)-ord(RS_F0)) mod 2 = 0 then
  1186. include(rg[R_FPUREGISTER].used_in_proc,succ(reg));
  1187. end;
  1188. end;
  1189. mask:=0;
  1190. nextoffset:=tcpuprocinfo(current_procinfo).intregstart;
  1191. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1192. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1193. include(saveregs,RS_R31);
  1194. if (pi_needs_stackframe in current_procinfo.flags) then
  1195. include(saveregs,RS_FRAME_POINTER_REG);
  1196. lastintoffset:=LocalSize;
  1197. framesave:=nil;
  1198. ra_save:=nil;
  1199. for reg:=RS_R1 to RS_R31 do
  1200. begin
  1201. if reg in saveregs then
  1202. begin
  1203. mask:=mask or (longword(1) shl ord(reg));
  1204. href.offset:=nextoffset;
  1205. lastintoffset:=nextoffset;
  1206. if (reg=RS_FRAME_POINTER_REG) then
  1207. framesave:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1208. else if (reg=RS_R31) then
  1209. ra_save:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1210. else
  1211. helplist.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1212. inc(nextoffset,4);
  1213. end;
  1214. end;
  1215. //list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,current_procinfo.para_stack_size));
  1216. list.concat(Taicpu.op_none(A_P_SET_NOMIPS16));
  1217. list.concat(Taicpu.op_reg_const_reg(A_P_FRAME,current_procinfo.framepointer,LocalSize,NR_R31));
  1218. list.concat(Taicpu.op_const_const(A_P_MASK,aint(mask),-(LocalSize-lastintoffset)));
  1219. list.concat(Taicpu.op_const_const(A_P_FMASK,aint(Fmask),-(LocalSize-lastfpuoffset)));
  1220. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1221. if tcpuprocinfo(current_procinfo).setnoat then
  1222. list.concat(Taicpu.op_none(A_P_SET_NOAT));
  1223. if (cs_create_pic in current_settings.moduleswitches) and
  1224. (pi_needs_got in current_procinfo.flags) then
  1225. begin
  1226. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1227. end;
  1228. if (-LocalSize >= simm16lo) and (-LocalSize <= simm16hi) then
  1229. begin
  1230. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1231. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-LocalSize));
  1232. if assigned(ra_save) then
  1233. list.concat(ra_save);
  1234. if assigned(framesave) then
  1235. begin
  1236. list.concat(framesave);
  1237. list.concat(Taicpu.op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,
  1238. NR_STACK_POINTER_REG,LocalSize));
  1239. end;
  1240. end
  1241. else
  1242. begin
  1243. a_load_const_reg(list,OS_32,-LocalSize,NR_R9);
  1244. list.concat(Taicpu.Op_reg_reg_reg(A_ADDU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R9));
  1245. if assigned(ra_save) then
  1246. list.concat(ra_save);
  1247. if assigned(framesave) then
  1248. begin
  1249. list.concat(framesave);
  1250. list.concat(Taicpu.op_reg_reg_reg(A_SUBU,NR_FRAME_POINTER_REG,
  1251. NR_STACK_POINTER_REG,NR_R9));
  1252. end;
  1253. { The instructions before are macros that can extend to multiple instructions,
  1254. the settings of R9 to -LocalSize surely does,
  1255. but the saving of RA and FP also might, and might
  1256. even use AT register, which is why we use R9 instead of AT here for -LocalSize }
  1257. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1258. end;
  1259. if (cs_create_pic in current_settings.moduleswitches) and
  1260. (pi_needs_got in current_procinfo.flags) then
  1261. begin
  1262. largeoffs:=(tcpuprocinfo(current_procinfo).save_gp_ref.offset>simm16hi);
  1263. if largeoffs then
  1264. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1265. list.concat(Taicpu.op_const(A_P_CPRESTORE,tcpuprocinfo(current_procinfo).save_gp_ref.offset));
  1266. if largeoffs then
  1267. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1268. end;
  1269. href.base:=NR_STACK_POINTER_REG;
  1270. for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
  1271. if tcpuprocinfo(current_procinfo).register_used[i] then
  1272. begin
  1273. reg:=parasupregs[i];
  1274. href.offset:=i*sizeof(aint)+LocalSize;
  1275. list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
  1276. end;
  1277. list.concatList(helplist);
  1278. helplist.Free;
  1279. if current_procinfo.has_nestedprocs then
  1280. current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@LocalSize);
  1281. end;
  1282. procedure TCGMIPS.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean);
  1283. var
  1284. href : treference;
  1285. stacksize : aint;
  1286. saveregs : tcpuregisterset;
  1287. nextoffset : aint;
  1288. reg : Tsuperregister;
  1289. begin
  1290. stacksize:=current_procinfo.calc_stackframe_size;
  1291. if nostackframe then
  1292. begin
  1293. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1294. list.concat(Taicpu.op_none(A_NOP));
  1295. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1296. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1297. end
  1298. else
  1299. begin
  1300. if tcpuprocinfo(current_procinfo).save_gp_ref.offset<>0 then
  1301. tg.ungettemp(list,tcpuprocinfo(current_procinfo).save_gp_ref);
  1302. reference_reset(href,0,[]);
  1303. href.base:=NR_STACK_POINTER_REG;
  1304. nextoffset:=tcpuprocinfo(current_procinfo).floatregstart;
  1305. for reg := RS_F0 to RS_F31 do
  1306. begin
  1307. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1308. begin
  1309. href.offset:=nextoffset;
  1310. list.concat(taicpu.op_reg_ref(A_LWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1311. inc(nextoffset,4);
  1312. end;
  1313. end;
  1314. nextoffset:=tcpuprocinfo(current_procinfo).intregstart;
  1315. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1316. if (current_procinfo.flags*[pi_do_call,pi_is_assembler]<>[]) then
  1317. include(saveregs,RS_R31);
  1318. if (pi_needs_stackframe in current_procinfo.flags) then
  1319. include(saveregs,RS_FRAME_POINTER_REG);
  1320. // GP does not need to be restored on exit
  1321. for reg:=RS_R1 to RS_R31 do
  1322. begin
  1323. if reg in saveregs then
  1324. begin
  1325. href.offset:=nextoffset;
  1326. list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1327. inc(nextoffset,sizeof(aint));
  1328. end;
  1329. end;
  1330. if (-stacksize >= simm16lo) and (-stacksize <= simm16hi) then
  1331. begin
  1332. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1333. { correct stack pointer in the delay slot }
  1334. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, stacksize));
  1335. end
  1336. else
  1337. begin
  1338. a_load_const_reg(list,OS_32,stacksize,NR_R1);
  1339. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1340. { correct stack pointer in the delay slot }
  1341. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R1));
  1342. tcpuprocinfo(current_procinfo).setnoat:=true;
  1343. end;
  1344. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1345. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1346. end;
  1347. list.concat(tai_directive.create(asd_ent_end,current_procinfo.procdef.mangledname));
  1348. end;
  1349. { ************* concatcopy ************ }
  1350. procedure TCGMIPS.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  1351. var
  1352. paraloc1, paraloc2, paraloc3: TCGPara;
  1353. pd: tprocdef;
  1354. begin
  1355. pd:=search_system_proc('MOVE');
  1356. paraloc1.init;
  1357. paraloc2.init;
  1358. paraloc3.init;
  1359. paramanager.getcgtempparaloc(list, pd, 1, paraloc1);
  1360. paramanager.getcgtempparaloc(list, pd, 2, paraloc2);
  1361. paramanager.getcgtempparaloc(list, pd, 3, paraloc3);
  1362. a_load_const_cgpara(list, OS_SINT, len, paraloc3);
  1363. a_loadaddr_ref_cgpara(list, dest, paraloc2);
  1364. a_loadaddr_ref_cgpara(list, Source, paraloc1);
  1365. paramanager.freecgpara(list, paraloc3);
  1366. paramanager.freecgpara(list, paraloc2);
  1367. paramanager.freecgpara(list, paraloc1);
  1368. alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1369. alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1370. a_call_name(list, 'FPC_MOVE', false);
  1371. dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1372. dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1373. paraloc3.done;
  1374. paraloc2.done;
  1375. paraloc1.done;
  1376. end;
  1377. procedure TCGMIPS.g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint);
  1378. var
  1379. tmpreg1, hreg, countreg: TRegister;
  1380. src, dst: TReference;
  1381. lab: tasmlabel;
  1382. Count, count2: aint;
  1383. function reference_is_reusable(const ref: treference): boolean;
  1384. begin
  1385. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1386. (ref.symbol=nil) and
  1387. (ref.offset>=simm16lo) and (ref.offset+len<=simm16hi);
  1388. end;
  1389. begin
  1390. if len > high(longint) then
  1391. internalerror(2002072704);
  1392. { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
  1393. allocated on stack. This can only be done before tcpuprocinfo.set_first_temp_offset,
  1394. i.e. before secondpass. Other internal procedures request correct stack frame
  1395. by setting pi_do_call during firstpass, but for this particular one it is impossible.
  1396. Therefore, if the current procedure is a leaf one, we have to leave it that way. }
  1397. { anybody wants to determine a good value here :)? }
  1398. if (len > 100) and
  1399. assigned(current_procinfo) and
  1400. (pi_do_call in current_procinfo.flags) then
  1401. g_concatcopy_move(list, Source, dest, len)
  1402. else
  1403. begin
  1404. Count := len div 4;
  1405. if (count<=4) and reference_is_reusable(source) then
  1406. src:=source
  1407. else
  1408. begin
  1409. reference_reset(src,sizeof(aint),source.volatility);
  1410. { load the address of source into src.base }
  1411. src.base := GetAddressRegister(list);
  1412. a_loadaddr_ref_reg(list, Source, src.base);
  1413. end;
  1414. if (count<=4) and reference_is_reusable(dest) then
  1415. dst:=dest
  1416. else
  1417. begin
  1418. reference_reset(dst,sizeof(aint),dest.volatility);
  1419. { load the address of dest into dst.base }
  1420. dst.base := GetAddressRegister(list);
  1421. a_loadaddr_ref_reg(list, dest, dst.base);
  1422. end;
  1423. { generate a loop }
  1424. if Count > 4 then
  1425. begin
  1426. countreg := GetIntRegister(list, OS_INT);
  1427. tmpreg1 := GetIntRegister(list, OS_INT);
  1428. a_load_const_reg(list, OS_INT, Count, countreg);
  1429. current_asmdata.getjumplabel(lab);
  1430. a_label(list, lab);
  1431. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1432. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1433. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4));
  1434. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4));
  1435. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1436. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1437. len := len mod 4;
  1438. end;
  1439. { unrolled loop }
  1440. Count := len div 4;
  1441. if Count > 0 then
  1442. begin
  1443. tmpreg1 := GetIntRegister(list, OS_INT);
  1444. for count2 := 1 to Count do
  1445. begin
  1446. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1447. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1448. Inc(src.offset, 4);
  1449. Inc(dst.offset, 4);
  1450. end;
  1451. len := len mod 4;
  1452. end;
  1453. if (len and 4) <> 0 then
  1454. begin
  1455. hreg := GetIntRegister(list, OS_INT);
  1456. a_load_ref_reg(list, OS_32, OS_32, src, hreg);
  1457. a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
  1458. Inc(src.offset, 4);
  1459. Inc(dst.offset, 4);
  1460. end;
  1461. { copy the leftovers }
  1462. if (len and 2) <> 0 then
  1463. begin
  1464. hreg := GetIntRegister(list, OS_INT);
  1465. a_load_ref_reg(list, OS_16, OS_16, src, hreg);
  1466. a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
  1467. Inc(src.offset, 2);
  1468. Inc(dst.offset, 2);
  1469. end;
  1470. if (len and 1) <> 0 then
  1471. begin
  1472. hreg := GetIntRegister(list, OS_INT);
  1473. a_load_ref_reg(list, OS_8, OS_8, src, hreg);
  1474. a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
  1475. end;
  1476. end;
  1477. end;
  1478. procedure TCGMIPS.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint);
  1479. var
  1480. src, dst: TReference;
  1481. tmpreg1, countreg: TRegister;
  1482. i: aint;
  1483. lab: tasmlabel;
  1484. begin
  1485. if (len > 31) and
  1486. { see comment in g_concatcopy }
  1487. assigned(current_procinfo) and
  1488. (pi_do_call in current_procinfo.flags) then
  1489. g_concatcopy_move(list, Source, dest, len)
  1490. else
  1491. begin
  1492. reference_reset(src,sizeof(aint),source.volatility);
  1493. reference_reset(dst,sizeof(aint),dest.volatility);
  1494. { load the address of source into src.base }
  1495. src.base := GetAddressRegister(list);
  1496. a_loadaddr_ref_reg(list, Source, src.base);
  1497. { load the address of dest into dst.base }
  1498. dst.base := GetAddressRegister(list);
  1499. a_loadaddr_ref_reg(list, dest, dst.base);
  1500. { generate a loop }
  1501. if len > 4 then
  1502. begin
  1503. countreg := GetIntRegister(list, OS_INT);
  1504. tmpreg1 := GetIntRegister(list, OS_INT);
  1505. a_load_const_reg(list, OS_INT, len, countreg);
  1506. current_asmdata.getjumplabel(lab);
  1507. a_label(list, lab);
  1508. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1509. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1510. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1));
  1511. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1));
  1512. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1513. a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_R0,countreg,lab);
  1514. end
  1515. else
  1516. begin
  1517. { unrolled loop }
  1518. tmpreg1 := GetIntRegister(list, OS_INT);
  1519. for i := 1 to len do
  1520. begin
  1521. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1522. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1523. Inc(src.offset);
  1524. Inc(dst.offset);
  1525. end;
  1526. end;
  1527. end;
  1528. end;
  1529. procedure TCGMIPS.g_profilecode(list:TAsmList);
  1530. var
  1531. href: treference;
  1532. begin
  1533. if not (cs_create_pic in current_settings.moduleswitches) then
  1534. begin
  1535. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('_gp',AT_DATA),0,sizeof(pint),[]);
  1536. a_loadaddr_ref_reg(list,href,NR_GP);
  1537. end;
  1538. list.concat(taicpu.op_reg_reg(A_MOVE,NR_R1,NR_RA));
  1539. list.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_SP,NR_SP,-8));
  1540. a_call_sym_pic(list,current_asmdata.RefAsmSymbol('_mcount',AT_FUNCTION));
  1541. tcpuprocinfo(current_procinfo).setnoat:=true;
  1542. end;
  1543. procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1544. begin
  1545. { This method is integrated into g_intf_wrapper and shouldn't be called separately }
  1546. InternalError(2013020102);
  1547. end;
  1548. {$ifndef mips64}
  1549. {****************************************************************************
  1550. TCG64_MIPSel
  1551. ****************************************************************************}
  1552. procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference);
  1553. var
  1554. tmpref: treference;
  1555. tmpreg: tregister;
  1556. begin
  1557. if target_info.endian = endian_big then
  1558. begin
  1559. tmpreg := reg.reglo;
  1560. reg.reglo := reg.reghi;
  1561. reg.reghi := tmpreg;
  1562. end;
  1563. tmpref := ref;
  1564. tcgmips(cg).make_simple_ref(list,tmpref);
  1565. list.concat(taicpu.op_reg_ref(A_SW,reg.reglo,tmpref));
  1566. Inc(tmpref.offset, 4);
  1567. list.concat(taicpu.op_reg_ref(A_SW,reg.reghi,tmpref));
  1568. end;
  1569. procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64);
  1570. var
  1571. tmpref: treference;
  1572. tmpreg: tregister;
  1573. begin
  1574. if target_info.endian = endian_big then
  1575. begin
  1576. tmpreg := reg.reglo;
  1577. reg.reglo := reg.reghi;
  1578. reg.reghi := tmpreg;
  1579. end;
  1580. tmpref := ref;
  1581. tcgmips(cg).make_simple_ref(list,tmpref);
  1582. list.concat(taicpu.op_reg_ref(A_LW,reg.reglo,tmpref));
  1583. Inc(tmpref.offset, 4);
  1584. list.concat(taicpu.op_reg_ref(A_LW,reg.reghi,tmpref));
  1585. end;
  1586. procedure TCg64MPSel.a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara);
  1587. var
  1588. hreg64: tregister64;
  1589. begin
  1590. { Override this function to prevent loading the reference twice.
  1591. Use here some extra registers, but those are optimized away by the RA }
  1592. hreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1593. hreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1594. a_load64_ref_reg(list, r, hreg64);
  1595. a_load64_reg_cgpara(list, hreg64, paraloc);
  1596. end;
  1597. procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64);
  1598. var
  1599. tmpreg1: TRegister;
  1600. begin
  1601. case op of
  1602. OP_NEG:
  1603. begin
  1604. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1605. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo));
  1606. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_R0, regdst.reglo));
  1607. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi));
  1608. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg1));
  1609. end;
  1610. OP_NOT:
  1611. begin
  1612. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo));
  1613. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi));
  1614. end;
  1615. else
  1616. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1617. end;
  1618. end;
  1619. procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64);
  1620. begin
  1621. a_op64_const_reg_reg(list, op, size, value, regdst, regdst);
  1622. end;
  1623. procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64);
  1624. var
  1625. l: tlocation;
  1626. begin
  1627. a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l);
  1628. end;
  1629. procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64);
  1630. var
  1631. l: tlocation;
  1632. begin
  1633. a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l);
  1634. end;
  1635. procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1636. var
  1637. tmplo,carry: TRegister;
  1638. hisize: tcgsize;
  1639. begin
  1640. carry:=NR_NO;
  1641. if (size in [OS_S64]) then
  1642. hisize:=OS_S32
  1643. else
  1644. hisize:=OS_32;
  1645. case op of
  1646. OP_AND,OP_OR,OP_XOR:
  1647. begin
  1648. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1649. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1650. end;
  1651. OP_ADD:
  1652. begin
  1653. if lo(value)<>0 then
  1654. begin
  1655. tmplo:=cg.GetIntRegister(list,OS_32);
  1656. carry:=cg.GetIntRegister(list,OS_32);
  1657. tcgmips(cg).handle_reg_const_reg(list,A_ADDU,regsrc.reglo,aint(lo(value)),tmplo);
  1658. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
  1659. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1660. end
  1661. else
  1662. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1663. { With overflow checking and unsigned args, this generates slighly suboptimal code
  1664. ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
  1665. look worth the effort. }
  1666. cg.a_op_const_reg_reg_checkoverflow(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1667. if carry<>NR_NO then
  1668. cg.a_op_reg_reg_reg_checkoverflow(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1669. end;
  1670. OP_SUB:
  1671. begin
  1672. carry:=NR_NO;
  1673. if lo(value)<>0 then
  1674. begin
  1675. tmplo:=cg.GetIntRegister(list,OS_32);
  1676. carry:=cg.GetIntRegister(list,OS_32);
  1677. tcgmips(cg).handle_reg_const_reg(list,A_SUBU,regsrc.reglo,aint(lo(value)),tmplo);
  1678. list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
  1679. cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
  1680. end
  1681. else
  1682. cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
  1683. cg.a_op_const_reg_reg_checkoverflow(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi,setflags,ovloc);
  1684. if carry<>NR_NO then
  1685. cg.a_op_reg_reg_reg_checkoverflow(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi,setflags,ovloc);
  1686. end;
  1687. else
  1688. InternalError(2013050301);
  1689. end;
  1690. end;
  1691. procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1692. var
  1693. tmplo,tmphi,carry,hreg: TRegister;
  1694. signed: boolean;
  1695. begin
  1696. case op of
  1697. OP_ADD:
  1698. begin
  1699. signed:=(size in [OS_S64]);
  1700. tmplo := cg.GetIntRegister(list,OS_S32);
  1701. carry := cg.GetIntRegister(list,OS_S32);
  1702. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1703. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1704. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
  1705. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1706. if signed or (not setflags) then
  1707. begin
  1708. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1709. list.concat(taicpu.op_reg_reg_reg(ops_add[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1710. end
  1711. else
  1712. begin
  1713. tmphi:=cg.GetIntRegister(list,OS_INT);
  1714. hreg:=cg.GetIntRegister(list,OS_INT);
  1715. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1716. // first add carry to one of the addends
  1717. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmphi, regsrc2.reghi, carry));
  1718. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
  1719. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1720. // then add another addend
  1721. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, tmphi, regsrc1.reghi));
  1722. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
  1723. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1724. end;
  1725. end;
  1726. OP_SUB:
  1727. begin
  1728. signed:=(size in [OS_S64]);
  1729. tmplo := cg.GetIntRegister(list,OS_S32);
  1730. carry := cg.GetIntRegister(list,OS_S32);
  1731. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1732. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmplo, regsrc2.reglo, regsrc1.reglo));
  1733. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
  1734. cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
  1735. if signed or (not setflags) then
  1736. begin
  1737. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1738. list.concat(taicpu.op_reg_reg_reg(ops_sub[setflags and signed], regdst.reghi, regdst.reghi, carry));
  1739. end
  1740. else
  1741. begin
  1742. tmphi:=cg.GetIntRegister(list,OS_INT);
  1743. hreg:=cg.GetIntRegister(list,OS_INT);
  1744. cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
  1745. // first subtract the carry...
  1746. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmphi, regsrc2.reghi, carry));
  1747. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
  1748. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1749. // ...then the subtrahend
  1750. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, tmphi, regsrc1.reghi));
  1751. list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
  1752. list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
  1753. end;
  1754. end;
  1755. OP_AND,OP_OR,OP_XOR:
  1756. begin
  1757. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1758. cg.a_op_reg_reg_reg(list,op,size,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1759. end;
  1760. else
  1761. internalerror(200306017);
  1762. end;
  1763. end;
  1764. {$endif mips64}
  1765. procedure create_codegen;
  1766. begin
  1767. cg:=TCGMIPS.Create;
  1768. {$ifndef mips64}
  1769. cg64:=TCg64MPSel.Create;
  1770. {$endif mips64}
  1771. end;
  1772. end.