cgcpu.pas 64 KB

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