cgcpu.pas 70 KB

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