cgcpu.pas 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183
  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. function getfpuregister(list: tasmlist; size: Tcgsize): Tregister; override;
  33. /// { needed by cg64 }
  34. procedure make_simple_ref(list: tasmlist; var ref: treference);
  35. procedure make_simple_ref_fpu(list: tasmlist; var ref: treference);
  36. procedure handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  37. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  38. { parameter }
  39. procedure a_loadaddr_ref_cgpara(list: tasmlist; const r: TReference; const paraloc: TCGPara); override;
  40. procedure a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override;
  41. procedure a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); override;
  42. procedure a_call_name(list: tasmlist; const s: string; weak : boolean); override;
  43. procedure a_call_reg(list: tasmlist; Reg: TRegister); override;
  44. { General purpose instructions }
  45. procedure a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister); override;
  46. procedure a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  47. procedure a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  48. procedure a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  49. procedure a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  50. procedure a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
  51. { move instructions }
  52. procedure a_load_const_reg(list: tasmlist; size: tcgsize; a: tcgint; reg: tregister); override;
  53. procedure a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference); override;
  54. procedure a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCgSize; reg: TRegister; const ref: TReference); override;
  55. procedure a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister); override;
  56. procedure a_load_reg_reg(list: tasmlist; FromSize, ToSize: TCgSize; reg1, reg2: tregister); override;
  57. procedure a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister); override;
  58. { fpu move instructions }
  59. procedure a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  60. procedure a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister); override;
  61. procedure a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference); override;
  62. { comparison operations }
  63. procedure a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  64. procedure a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  65. procedure a_jmp_always(List: tasmlist; l: TAsmLabel); override;
  66. procedure a_jmp_name(list: tasmlist; const s: string); override;
  67. procedure g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); override;
  68. procedure g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation); override;
  69. procedure g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean); override;
  70. procedure g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean); override;
  71. procedure g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  72. procedure g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint); override;
  73. procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  74. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  75. procedure g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint); override;
  76. procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);override;
  77. { Transform unsupported methods into Internal errors }
  78. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  79. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  80. procedure maybe_reload_gp(list : tasmlist);
  81. procedure Load_PIC_Addr(list : tasmlist; tmpreg : Tregister;
  82. var ref : treference);
  83. end;
  84. TCg64MPSel = class(tcg64f32)
  85. public
  86. procedure a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference); override;
  87. procedure a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64); override;
  88. procedure a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara); override;
  89. procedure a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64); override;
  90. procedure a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64); override;
  91. procedure a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64); override;
  92. procedure a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64); override;
  93. procedure a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  94. procedure a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override;
  95. end;
  96. 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. function f_TOpCG2AsmOp(op: TOpCG; size: tcgsize): TAsmOp;
  109. begin
  110. if size = OS_32 then
  111. case op of
  112. OP_ADD: { simple addition }
  113. f_TOpCG2AsmOp := A_ADDU;
  114. OP_AND: { simple logical and }
  115. f_TOpCG2AsmOp := A_AND;
  116. OP_DIV: { simple unsigned division }
  117. f_TOpCG2AsmOp := A_DIVU;
  118. OP_IDIV: { simple signed division }
  119. f_TOpCG2AsmOp := A_DIV;
  120. OP_IMUL: { simple signed multiply }
  121. f_TOpCG2AsmOp := A_MULT;
  122. OP_MUL: { simple unsigned multiply }
  123. f_TOpCG2AsmOp := A_MULTU;
  124. OP_NEG: { simple negate }
  125. f_TOpCG2AsmOp := A_NEGU;
  126. OP_NOT: { simple logical not }
  127. f_TOpCG2AsmOp := A_NOT;
  128. OP_OR: { simple logical or }
  129. f_TOpCG2AsmOp := A_OR;
  130. OP_SAR: { arithmetic shift-right }
  131. f_TOpCG2AsmOp := A_SRA;
  132. OP_SHL: { logical shift left }
  133. f_TOpCG2AsmOp := A_SLL;
  134. OP_SHR: { logical shift right }
  135. f_TOpCG2AsmOp := A_SRL;
  136. OP_SUB: { simple subtraction }
  137. f_TOpCG2AsmOp := A_SUBU;
  138. OP_XOR: { simple exclusive or }
  139. f_TOpCG2AsmOp := A_XOR;
  140. else
  141. InternalError(2007070401);
  142. end{ case }
  143. else
  144. case op of
  145. OP_ADD: { simple addition }
  146. f_TOpCG2AsmOp := A_ADDU;
  147. OP_AND: { simple logical and }
  148. f_TOpCG2AsmOp := A_AND;
  149. OP_DIV: { simple unsigned division }
  150. f_TOpCG2AsmOp := A_DIVU;
  151. OP_IDIV: { simple signed division }
  152. f_TOpCG2AsmOp := A_DIV;
  153. OP_IMUL: { simple signed multiply }
  154. f_TOpCG2AsmOp := A_MULT;
  155. OP_MUL: { simple unsigned multiply }
  156. f_TOpCG2AsmOp := A_MULTU;
  157. OP_NEG: { simple negate }
  158. f_TOpCG2AsmOp := A_NEGU;
  159. OP_NOT: { simple logical not }
  160. f_TOpCG2AsmOp := A_NOT;
  161. OP_OR: { simple logical or }
  162. f_TOpCG2AsmOp := A_OR;
  163. OP_SAR: { arithmetic shift-right }
  164. f_TOpCG2AsmOp := A_SRA;
  165. OP_SHL: { logical shift left }
  166. f_TOpCG2AsmOp := A_SLL;
  167. OP_SHR: { logical shift right }
  168. f_TOpCG2AsmOp := A_SRL;
  169. OP_SUB: { simple subtraction }
  170. f_TOpCG2AsmOp := A_SUBU;
  171. OP_XOR: { simple exclusive or }
  172. f_TOpCG2AsmOp := A_XOR;
  173. else
  174. InternalError(2007010701);
  175. end;{ case }
  176. end;
  177. function f_TOpCG2AsmOp_ovf(op: TOpCG; size: tcgsize): TAsmOp;
  178. begin
  179. if size = OS_32 then
  180. case op of
  181. OP_ADD: { simple addition }
  182. f_TOpCG2AsmOp_ovf := A_ADD;
  183. OP_AND: { simple logical and }
  184. f_TOpCG2AsmOp_ovf := A_AND;
  185. OP_DIV: { simple unsigned division }
  186. f_TOpCG2AsmOp_ovf := A_DIVU;
  187. OP_IDIV: { simple signed division }
  188. f_TOpCG2AsmOp_ovf := A_DIV;
  189. OP_IMUL: { simple signed multiply }
  190. f_TOpCG2AsmOp_ovf := A_MULO;
  191. OP_MUL: { simple unsigned multiply }
  192. f_TOpCG2AsmOp_ovf := A_MULOU;
  193. OP_NEG: { simple negate }
  194. f_TOpCG2AsmOp_ovf := A_NEG;
  195. OP_NOT: { simple logical not }
  196. f_TOpCG2AsmOp_ovf := A_NOT;
  197. OP_OR: { simple logical or }
  198. f_TOpCG2AsmOp_ovf := A_OR;
  199. OP_SAR: { arithmetic shift-right }
  200. f_TOpCG2AsmOp_ovf := A_SRA;
  201. OP_SHL: { logical shift left }
  202. f_TOpCG2AsmOp_ovf := A_SLL;
  203. OP_SHR: { logical shift right }
  204. f_TOpCG2AsmOp_ovf := A_SRL;
  205. OP_SUB: { simple subtraction }
  206. f_TOpCG2AsmOp_ovf := A_SUB;
  207. OP_XOR: { simple exclusive or }
  208. f_TOpCG2AsmOp_ovf := A_XOR;
  209. else
  210. InternalError(2007070403);
  211. end{ case }
  212. else
  213. case op of
  214. OP_ADD: { simple addition }
  215. f_TOpCG2AsmOp_ovf := A_ADD;
  216. OP_AND: { simple logical and }
  217. f_TOpCG2AsmOp_ovf := A_AND;
  218. OP_DIV: { simple unsigned division }
  219. f_TOpCG2AsmOp_ovf := A_DIVU;
  220. OP_IDIV: { simple signed division }
  221. f_TOpCG2AsmOp_ovf := A_DIV;
  222. OP_IMUL: { simple signed multiply }
  223. f_TOpCG2AsmOp_ovf := A_MULO;
  224. OP_MUL: { simple unsigned multiply }
  225. f_TOpCG2AsmOp_ovf := A_MULOU;
  226. OP_NEG: { simple negate }
  227. f_TOpCG2AsmOp_ovf := A_NEG;
  228. OP_NOT: { simple logical not }
  229. f_TOpCG2AsmOp_ovf := A_NOT;
  230. OP_OR: { simple logical or }
  231. f_TOpCG2AsmOp_ovf := A_OR;
  232. OP_SAR: { arithmetic shift-right }
  233. f_TOpCG2AsmOp_ovf := A_SRA;
  234. OP_SHL: { logical shift left }
  235. f_TOpCG2AsmOp_ovf := A_SLL;
  236. OP_SHR: { logical shift right }
  237. f_TOpCG2AsmOp_ovf := A_SRL;
  238. OP_SUB: { simple subtraction }
  239. f_TOpCG2AsmOp_ovf := A_SUB;
  240. OP_XOR: { simple exclusive or }
  241. f_TOpCG2AsmOp_ovf := A_XOR;
  242. else
  243. InternalError(2007010703);
  244. end;{ case }
  245. end;
  246. function f_TOp64CG2AsmOp(op: TOpCG): TAsmOp;
  247. begin
  248. case op of
  249. OP_ADD: { simple addition }
  250. f_TOp64CG2AsmOp := A_DADDU;
  251. OP_AND: { simple logical and }
  252. f_TOp64CG2AsmOp := A_AND;
  253. OP_DIV: { simple unsigned division }
  254. f_TOp64CG2AsmOp := A_DDIVU;
  255. OP_IDIV: { simple signed division }
  256. f_TOp64CG2AsmOp := A_DDIV;
  257. OP_IMUL: { simple signed multiply }
  258. f_TOp64CG2AsmOp := A_DMULO;
  259. OP_MUL: { simple unsigned multiply }
  260. f_TOp64CG2AsmOp := A_DMULOU;
  261. OP_NEG: { simple negate }
  262. f_TOp64CG2AsmOp := A_DNEGU;
  263. OP_NOT: { simple logical not }
  264. f_TOp64CG2AsmOp := A_NOT;
  265. OP_OR: { simple logical or }
  266. f_TOp64CG2AsmOp := A_OR;
  267. OP_SAR: { arithmetic shift-right }
  268. f_TOp64CG2AsmOp := A_DSRA;
  269. OP_SHL: { logical shift left }
  270. f_TOp64CG2AsmOp := A_DSLL;
  271. OP_SHR: { logical shift right }
  272. f_TOp64CG2AsmOp := A_DSRL;
  273. OP_SUB: { simple subtraction }
  274. f_TOp64CG2AsmOp := A_DSUBU;
  275. OP_XOR: { simple exclusive or }
  276. f_TOp64CG2AsmOp := A_XOR;
  277. else
  278. InternalError(2007010702);
  279. end;{ case }
  280. end;
  281. procedure TCGMIPS.make_simple_ref(list: tasmlist; var ref: treference);
  282. var
  283. tmpreg, tmpreg1: tregister;
  284. tmpref: treference;
  285. begin
  286. tmpreg := NR_NO;
  287. { Be sure to have a base register }
  288. if (ref.base = NR_NO) then
  289. begin
  290. ref.base := ref.index;
  291. ref.index := NR_NO;
  292. end;
  293. if (ref.refaddr in [addr_pic,addr_pic_call16]) then
  294. maybe_reload_gp(list);
  295. if ((cs_create_pic in current_settings.moduleswitches) or
  296. (ref.refaddr in [addr_pic,addr_pic_call16])) and
  297. assigned(ref.symbol) then
  298. begin
  299. tmpreg := cg.GetIntRegister(list, OS_INT);
  300. Load_PIC_Addr(list,tmpreg,ref);
  301. { ref.symbol is nil now, but we cannot reuse tmpreg below,
  302. thus we need to reset it here, otherwise wrong code is generated }
  303. tmpreg:=NR_NO;
  304. end;
  305. { When need to use LUI, do it first }
  306. if assigned(ref.symbol) or
  307. (ref.offset < simm16lo) or
  308. (ref.offset > simm16hi) then
  309. begin
  310. if tmpreg=NR_NO then
  311. tmpreg := GetIntRegister(list, OS_INT);
  312. reference_reset(tmpref,sizeof(aint));
  313. tmpref.symbol := ref.symbol;
  314. tmpref.offset := ref.offset;
  315. tmpref.refaddr := addr_high;
  316. list.concat(taicpu.op_reg_ref(A_LUI, tmpreg, tmpref));
  317. if (ref.offset = 0) and (ref.index = NR_NO) and
  318. (ref.base = NR_NO) then
  319. begin
  320. ref.refaddr := addr_low;
  321. end
  322. else
  323. begin
  324. { Load the low part is left }
  325. tmpref.refaddr := addr_low;
  326. list.concat(taicpu.op_reg_reg_ref(A_ADDIU, tmpreg, tmpreg, tmpref));
  327. ref.offset := 0;
  328. { symbol is loaded }
  329. ref.symbol := nil;
  330. end;
  331. if (ref.index <> NR_NO) then
  332. begin
  333. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.index, tmpreg));
  334. ref.index := tmpreg;
  335. end
  336. else
  337. begin
  338. if ref.base <> NR_NO then
  339. ref.index := tmpreg
  340. else
  341. ref.base := tmpreg;
  342. end;
  343. end;
  344. if (ref.base <> NR_NO) then
  345. begin
  346. if (ref.index <> NR_NO) and (ref.offset = 0) then
  347. begin
  348. tmpreg1 := GetIntRegister(list, OS_INT);
  349. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.base, ref.index));
  350. ref.base := tmpreg1;
  351. ref.index := NR_NO;
  352. end
  353. else if (ref.index <> NR_NO) and
  354. ((ref.offset <> 0) or assigned(ref.symbol)) then
  355. begin
  356. if tmpreg = NR_NO then
  357. tmpreg := GetIntRegister(list, OS_INT);
  358. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.base, ref.index));
  359. ref.base := tmpreg;
  360. ref.index := NR_NO;
  361. end;
  362. end;
  363. end;
  364. procedure TCGMIPS.make_simple_ref_fpu(list: tasmlist; var ref: treference);
  365. var
  366. tmpreg, tmpreg1: tregister;
  367. tmpref: treference;
  368. begin
  369. tmpreg := NR_NO;
  370. { Be sure to have a base register }
  371. if (ref.base = NR_NO) then
  372. begin
  373. ref.base := ref.index;
  374. ref.index := NR_NO;
  375. end;
  376. if (ref.refaddr in [addr_pic,addr_pic_call16]) then
  377. maybe_reload_gp(list);
  378. if ((cs_create_pic in current_settings.moduleswitches) or
  379. (ref.refaddr in [addr_pic,addr_pic_call16])) and
  380. assigned(ref.symbol) then
  381. begin
  382. tmpreg := GetIntRegister(list, OS_ADDR);
  383. Load_PIC_Addr(list,tmpreg,ref);
  384. if (ref.base=NR_NO) and (ref.offset=0) then
  385. exit;
  386. end;
  387. { When need to use LUI, do it first }
  388. if (not assigned(ref.symbol)) and (ref.index = NR_NO) and
  389. (ref.offset > simm16lo + 1000) and (ref.offset < simm16hi - 1000)
  390. then
  391. exit;
  392. tmpreg1 := GetIntRegister(list, OS_INT);
  393. if assigned(ref.symbol) then
  394. begin
  395. reference_reset(tmpref,sizeof(aint));
  396. tmpref.symbol := ref.symbol;
  397. tmpref.offset := ref.offset;
  398. tmpref.refaddr := addr_high;
  399. list.concat(taicpu.op_reg_ref(A_LUI, tmpreg1, tmpref));
  400. { Load the low part }
  401. tmpref.refaddr := addr_low;
  402. list.concat(taicpu.op_reg_reg_ref(A_ADDIU, tmpreg1, tmpreg1, tmpref));
  403. { symbol is loaded }
  404. ref.symbol := nil;
  405. end
  406. else
  407. list.concat(taicpu.op_reg_const(A_LI, tmpreg1, ref.offset));
  408. if (ref.index <> NR_NO) then
  409. begin
  410. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.index, tmpreg1));
  411. ref.index := NR_NO
  412. end;
  413. if ref.base <> NR_NO then
  414. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.base, tmpreg1));
  415. ref.base := tmpreg1;
  416. ref.offset := 0;
  417. end;
  418. procedure TCGMIPS.handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: tcgint; dst: tregister);
  419. var
  420. tmpreg: tregister;
  421. begin
  422. if (a < simm16lo) or
  423. (a > simm16hi) then
  424. begin
  425. tmpreg := GetIntRegister(list, OS_INT);
  426. a_load_const_reg(list, OS_INT, a, tmpreg);
  427. list.concat(taicpu.op_reg_reg_reg(op, dst, src, tmpreg));
  428. end
  429. else
  430. list.concat(taicpu.op_reg_reg_const(op, dst, src, a));
  431. end;
  432. {****************************************************************************
  433. Assembler code
  434. ****************************************************************************}
  435. procedure TCGMIPS.init_register_allocators;
  436. begin
  437. inherited init_register_allocators;
  438. { Keep RS_R25, i.e. $t9 for PIC call }
  439. if (cs_create_pic in current_settings.moduleswitches) and assigned(current_procinfo) and
  440. (pi_needs_got in current_procinfo.flags) then
  441. begin
  442. current_procinfo.got := NR_GP;
  443. rg[R_INTREGISTER] := Trgcpu.Create(R_INTREGISTER, R_SUBD,
  444. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  445. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  446. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  447. first_int_imreg, []);
  448. end
  449. else
  450. rg[R_INTREGISTER] := trgcpu.Create(R_INTREGISTER, R_SUBD,
  451. [RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  452. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  453. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24{,RS_R25}],
  454. first_int_imreg, []);
  455. {
  456. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  457. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
  458. RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,
  459. RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23,
  460. RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31],
  461. first_fpu_imreg, []);
  462. }
  463. rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS,
  464. [RS_F0,RS_F2,RS_F4,RS_F6, RS_F8,RS_F10,RS_F12,RS_F14,
  465. RS_F16,RS_F18,RS_F20,RS_F22, RS_F24,RS_F26,RS_F28,RS_F30],
  466. first_fpu_imreg, []);
  467. { needs at least one element for rgobj not to crash }
  468. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  469. [RS_R0],first_mm_imreg,[]);
  470. end;
  471. procedure TCGMIPS.done_register_allocators;
  472. begin
  473. rg[R_INTREGISTER].Free;
  474. rg[R_FPUREGISTER].Free;
  475. rg[R_MMREGISTER].Free;
  476. inherited done_register_allocators;
  477. end;
  478. function TCGMIPS.getfpuregister(list: tasmlist; size: Tcgsize): Tregister;
  479. begin
  480. if size = OS_F64 then
  481. Result := rg[R_FPUREGISTER].getregister(list, R_SUBFD)
  482. else
  483. Result := rg[R_FPUREGISTER].getregister(list, R_SUBFS);
  484. end;
  485. procedure TCGMIPS.a_loadaddr_ref_cgpara(list: tasmlist; const r: TReference; const paraloc: TCGPara);
  486. var
  487. Ref: TReference;
  488. TmpReg: TRegister;
  489. begin
  490. paraloc.check_simple_location;
  491. paramanager.allocparaloc(list,paraloc.location);
  492. with paraloc.location^ do
  493. begin
  494. case loc of
  495. LOC_REGISTER, LOC_CREGISTER:
  496. a_loadaddr_ref_reg(list, r, Register);
  497. LOC_REFERENCE:
  498. begin
  499. reference_reset(ref,sizeof(aint));
  500. ref.base := reference.index;
  501. ref.offset := reference.offset;
  502. tmpreg := GetAddressRegister(list);
  503. a_loadaddr_ref_reg(list, r, tmpreg);
  504. a_load_reg_ref(list, OS_ADDR, OS_ADDR, tmpreg, ref);
  505. end;
  506. else
  507. internalerror(2002080701);
  508. end;
  509. end;
  510. end;
  511. procedure TCGMIPS.a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara);
  512. var
  513. href, href2: treference;
  514. hloc: pcgparalocation;
  515. begin
  516. { TODO: inherited cannot deal with individual locations for each of OS_32 registers.
  517. Must change parameter management to allocate a single 64-bit register pair,
  518. then this method can be removed. }
  519. href := ref;
  520. hloc := paraloc.location;
  521. while assigned(hloc) do
  522. begin
  523. paramanager.allocparaloc(list,hloc);
  524. case hloc^.loc of
  525. LOC_REGISTER:
  526. a_load_ref_reg(list, hloc^.size, hloc^.size, href, hloc^.Register);
  527. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  528. a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  529. LOC_REFERENCE:
  530. begin
  531. paraloc.check_simple_location;
  532. reference_reset_base(href2,paraloc.location^.reference.index,paraloc.location^.reference.offset,paraloc.alignment);
  533. { concatcopy should choose the best way to copy the data }
  534. g_concatcopy(list,ref,href2,tcgsize2size[size]);
  535. end;
  536. else
  537. internalerror(200408241);
  538. end;
  539. Inc(href.offset, tcgsize2size[hloc^.size]);
  540. hloc := hloc^.Next;
  541. end;
  542. end;
  543. procedure TCGMIPS.a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara);
  544. var
  545. href: treference;
  546. begin
  547. if paraloc.Location^.next=nil then
  548. begin
  549. inherited a_loadfpu_reg_cgpara(list,size,r,paraloc);
  550. exit;
  551. end;
  552. tg.GetTemp(list, TCGSize2Size[size], TCGSize2Size[size], tt_normal, href);
  553. a_loadfpu_reg_ref(list, size, size, r, href);
  554. a_loadfpu_ref_cgpara(list, size, href, paraloc);
  555. tg.Ungettemp(list, href);
  556. end;
  557. procedure TCGMIPS.a_call_name(list: tasmlist; const s: string; weak: boolean);
  558. var
  559. href: treference;
  560. begin
  561. if assigned(current_procinfo) and
  562. not (pi_do_call in current_procinfo.flags) then
  563. InternalError(2013022101);
  564. if (cs_create_pic in current_settings.moduleswitches) then
  565. begin
  566. reference_reset(href,sizeof(aint));
  567. href.symbol:=current_asmdata.RefAsmSymbol(s);
  568. a_loadaddr_ref_reg(list,href,NR_PIC_FUNC);
  569. { JAL handled as macro provides delay slot and correct restoring of GP. }
  570. { Doing it ourselves requires a fixup pass, because GP restore location
  571. becomes known only in g_proc_entry, when all code is already generated. }
  572. { GAS <2.21 is buggy, it doesn't add delay slot in noreorder mode. As a result,
  573. the code will crash if dealing with stack frame size >32767 or if calling
  574. into shared library.
  575. This can be remedied by enabling instruction reordering, but then we also
  576. have to emit .set macro/.set nomacro pair and exclude JAL from the
  577. list of macro instructions (because noreorder is not allowed after nomacro) }
  578. list.concat(taicpu.op_none(A_P_SET_MACRO));
  579. list.concat(taicpu.op_none(A_P_SET_REORDER));
  580. list.concat(taicpu.op_reg(A_JAL,NR_PIC_FUNC));
  581. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  582. list.concat(taicpu.op_none(A_P_SET_NOMACRO));
  583. end
  584. else
  585. begin
  586. list.concat(taicpu.op_sym(A_JAL,current_asmdata.RefAsmSymbol(s)));
  587. { Delay slot }
  588. list.concat(taicpu.op_none(A_NOP));
  589. end;
  590. end;
  591. procedure TCGMIPS.a_call_reg(list: tasmlist; Reg: TRegister);
  592. begin
  593. if assigned(current_procinfo) and
  594. not (pi_do_call in current_procinfo.flags) then
  595. InternalError(2013022102);
  596. if (cs_create_pic in current_settings.moduleswitches) then
  597. begin
  598. if (Reg <> NR_PIC_FUNC) then
  599. list.concat(taicpu.op_reg_reg(A_MOVE,NR_PIC_FUNC,reg));
  600. { See comments in a_call_name }
  601. list.concat(taicpu.op_none(A_P_SET_MACRO));
  602. list.concat(taicpu.op_none(A_P_SET_REORDER));
  603. list.concat(taicpu.op_reg(A_JAL,NR_PIC_FUNC));
  604. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  605. list.concat(taicpu.op_none(A_P_SET_NOMACRO));
  606. end
  607. else
  608. begin
  609. list.concat(taicpu.op_reg(A_JALR, reg));
  610. { Delay slot }
  611. list.concat(taicpu.op_none(A_NOP));
  612. end;
  613. end;
  614. {********************** load instructions ********************}
  615. procedure TCGMIPS.a_load_const_reg(list: tasmlist; size: TCGSize; a: tcgint; reg: TRegister);
  616. begin
  617. if (a = 0) then
  618. list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0))
  619. { LUI allows to set the upper 16 bits, so we'll take full advantage of it }
  620. else if (a and aint($ffff)) = 0 then
  621. list.concat(taicpu.op_reg_const(A_LUI, reg, aint(a) shr 16))
  622. else if (a >= simm16lo) and (a <= simm16hi) then
  623. list.concat(taicpu.op_reg_reg_const(A_ADDIU, reg, NR_R0, a))
  624. else if (a>=0) and (a <= 65535) then
  625. list.concat(taicpu.op_reg_reg_const(A_ORI, reg, NR_R0, a))
  626. else
  627. begin
  628. list.concat(taicpu.op_reg_const(A_LI, reg, aint(a) ));
  629. end;
  630. end;
  631. procedure TCGMIPS.a_load_const_ref(list: tasmlist; size: tcgsize; a: tcgint; const ref: TReference);
  632. begin
  633. if a = 0 then
  634. a_load_reg_ref(list, size, size, NR_R0, ref)
  635. else
  636. inherited a_load_const_ref(list, size, a, ref);
  637. end;
  638. procedure TCGMIPS.a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCGSize; reg: tregister; const Ref: TReference);
  639. var
  640. op: tasmop;
  641. href: treference;
  642. begin
  643. if (TCGSize2Size[fromsize] < TCGSize2Size[tosize]) then
  644. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  645. case tosize of
  646. OS_8,
  647. OS_S8:
  648. Op := A_SB;
  649. OS_16,
  650. OS_S16:
  651. Op := A_SH;
  652. OS_32,
  653. OS_S32:
  654. Op := A_SW;
  655. else
  656. InternalError(2002122100);
  657. end;
  658. href:=ref;
  659. make_simple_ref(list,href);
  660. list.concat(taicpu.op_reg_ref(op,reg,href));
  661. end;
  662. procedure TCGMIPS.a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister);
  663. var
  664. op: tasmop;
  665. href: treference;
  666. begin
  667. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  668. fromsize := tosize;
  669. case fromsize of
  670. OS_S8:
  671. Op := A_LB;{Load Signed Byte}
  672. OS_8:
  673. Op := A_LBU;{Load Unsigned Byte}
  674. OS_S16:
  675. Op := A_LH;{Load Signed Halfword}
  676. OS_16:
  677. Op := A_LHU;{Load Unsigned Halfword}
  678. OS_S32:
  679. Op := A_LW;{Load Word}
  680. OS_32:
  681. Op := A_LW;//A_LWU;{Load Unsigned Word}
  682. OS_S64,
  683. OS_64:
  684. Op := A_LD;{Load a Long Word}
  685. else
  686. InternalError(2002122101);
  687. end;
  688. href:=ref;
  689. make_simple_ref(list,href);
  690. list.concat(taicpu.op_reg_ref(op,reg,href));
  691. if (fromsize=OS_S8) and (tosize=OS_16) then
  692. a_load_reg_reg(list,fromsize,tosize,reg,reg);
  693. end;
  694. procedure TCGMIPS.a_load_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  695. var
  696. instr: taicpu;
  697. begin
  698. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  699. (
  700. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and (tosize <> fromsize)
  701. ) or ((fromsize = OS_S8) and
  702. (tosize = OS_16)) then
  703. begin
  704. case tosize of
  705. OS_8:
  706. a_op_const_reg_reg(list, OP_AND, tosize, $ff, reg1, reg2);
  707. OS_16:
  708. a_op_const_reg_reg(list, OP_AND, tosize, $ffff, reg1, reg2);
  709. OS_32,
  710. OS_S32:
  711. begin
  712. instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1);
  713. list.Concat(instr);
  714. { Notify the register allocator that we have written a move instruction so
  715. it can try to eliminate it. }
  716. add_move_instruction(instr);
  717. end;
  718. OS_S8:
  719. begin
  720. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 24));
  721. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 24));
  722. end;
  723. OS_S16:
  724. begin
  725. list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 16));
  726. list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 16));
  727. end;
  728. else
  729. internalerror(2002090901);
  730. end;
  731. end
  732. else
  733. begin
  734. if reg1 <> reg2 then
  735. begin
  736. { same size, only a register mov required }
  737. instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1);
  738. list.Concat(instr);
  739. // { Notify the register allocator that we have written a move instruction so
  740. // it can try to eliminate it. }
  741. add_move_instruction(instr);
  742. end;
  743. end;
  744. end;
  745. procedure TCGMIPS.maybe_reload_gp(list : tasmlist);
  746. var
  747. tmpref: treference;
  748. begin
  749. if not (cs_create_pic in current_settings.moduleswitches) then
  750. begin
  751. list.concat(tai_comment.create(
  752. strpnew('Reloading _gp for non-pic code')));
  753. reference_reset(tmpref,sizeof(aint));
  754. tmpref.symbol:=current_asmdata.RefAsmSymbol('_gp');
  755. cg.a_loadaddr_ref_reg(list,tmpref,NR_GP);
  756. end;
  757. end;
  758. procedure TCGMIPS.Load_PIC_Addr(list : tasmlist; tmpreg : Tregister;
  759. var ref : treference);
  760. var
  761. tmpref : treference;
  762. begin
  763. reference_reset(tmpref,sizeof(aint));
  764. tmpref.symbol := ref.symbol;
  765. { This only works correctly if pic generation is used,
  766. so that -KPIC option is passed to GNU assembler }
  767. if (cs_create_pic in current_settings.moduleswitches) then
  768. begin
  769. tmpref.refaddr:=addr_full;
  770. list.concat(taicpu.op_reg_ref(A_LA, tmpreg, tmpref));
  771. end
  772. else
  773. begin
  774. if (ref.refaddr=addr_pic_call16) or (ref.symbol.typ=AT_FUNCTION) then
  775. begin
  776. list.concat(tai_comment.create(strpnew('loadaddr pic %call16 code')));
  777. tmpref.refaddr := addr_pic_call16;
  778. end
  779. else
  780. begin
  781. list.concat(tai_comment.create(strpnew('loadaddr pic %got code')));
  782. tmpref.refaddr := addr_pic;
  783. end;
  784. if not (pi_needs_got in current_procinfo.flags) then
  785. internalerror(200501161);
  786. if current_procinfo.got=NR_NO then
  787. current_procinfo.got:=NR_GP;
  788. { for addr_pic NR_GP can be implicit or explicit }
  789. if ref.refaddr in [addr_pic,addr_pic_call16] then
  790. begin
  791. if (ref.base=current_procinfo.got) then
  792. ref.base:=NR_NO;
  793. if (ref.index=current_procinfo.got) then
  794. ref.index:=NR_NO;
  795. end;
  796. tmpref.base := current_procinfo.got;
  797. list.concat(taicpu.op_reg_ref(A_LW, tmpreg, tmpref));
  798. if (tmpref.refaddr<>addr_pic_call16) {and
  799. and (ref.symbol is TAsmSymbolSect) and
  800. (TAsmSymbolSect(ref.symbol).sectype in needs_pic_lo16_set)} then
  801. begin
  802. { GOT also requires loading of low part }
  803. { but apparently only for some type of sumbols :( }
  804. list.concat(tai_comment.create(strpnew('pic %lo code')));
  805. tmpref.refaddr := addr_low;
  806. tmpref.base := NR_NO;
  807. list.concat(taicpu.op_reg_reg_ref(A_ADDIU, tmpreg, tmpreg, tmpref));
  808. end;
  809. end;
  810. ref.symbol:=nil;
  811. { This is now a normal addr reference }
  812. ref.refaddr:=addr_no;
  813. if (ref.index <> NR_NO) then
  814. begin
  815. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.index, tmpreg));
  816. ref.index := tmpreg;
  817. end
  818. else
  819. begin
  820. if ref.base <> NR_NO then
  821. ref.index := tmpreg
  822. else
  823. ref.base := tmpreg;
  824. end;
  825. end;
  826. procedure TCGMIPS.a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister);
  827. var
  828. tmpref, href: treference;
  829. hreg, tmpreg: tregister;
  830. r_used: boolean;
  831. begin
  832. r_used := false;
  833. href := ref;
  834. if (href.base = NR_NO) and (href.index <> NR_NO) then
  835. internalerror(200306171);
  836. if ((cs_create_pic in current_settings.moduleswitches) or
  837. (ref.refaddr in [addr_pic,addr_pic_call16])) and
  838. assigned(href.symbol) then
  839. begin
  840. Load_PIC_Addr(list,r,href);
  841. r_used := true;
  842. if (href.base=NR_NO) and (href.offset=0) then
  843. exit;
  844. end;
  845. if assigned(href.symbol) or
  846. (href.offset < simm16lo) or
  847. (href.offset > simm16hi) then
  848. begin
  849. if (href.base = NR_NO) and (href.index = NR_NO) then
  850. hreg := r
  851. else
  852. hreg := GetAddressRegister(list);
  853. reference_reset(tmpref,sizeof(aint));
  854. tmpref.symbol := href.symbol;
  855. tmpref.offset := href.offset;
  856. tmpref.refaddr := addr_high;
  857. list.concat(taicpu.op_reg_ref(A_LUI, hreg, tmpref));
  858. { Only the low part is left }
  859. tmpref.refaddr := addr_low;
  860. list.concat(taicpu.op_reg_reg_ref(A_ADDIU, hreg, hreg, tmpref));
  861. if href.base <> NR_NO then
  862. begin
  863. if href.index <> NR_NO then
  864. begin
  865. list.concat(taicpu.op_reg_reg_reg(A_ADDU, hreg, href.base, hreg));
  866. list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.index));
  867. end
  868. else
  869. list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.base));
  870. end;
  871. end
  872. else
  873. { At least small offset, maybe base and maybe index }
  874. if (href.offset >= simm16lo) and
  875. (href.offset <= simm16hi) then
  876. begin
  877. if href.index <> NR_NO then { Both base and index }
  878. begin
  879. if href.offset = 0 then
  880. begin
  881. list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, href.base, href.index));
  882. end
  883. else
  884. begin
  885. if r_used then
  886. hreg := GetAddressRegister(list)
  887. else
  888. hreg := r;
  889. list.concat(taicpu.op_reg_reg_const(A_ADDIU, hreg, href.base, href.offset));
  890. list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.index));
  891. end
  892. end
  893. else if href.base <> NR_NO then { Only base }
  894. begin
  895. if (href.offset<>0) or (r<>href.base) then
  896. list.concat(taicpu.op_reg_reg_const(A_ADDIU, r, href.base, href.offset));
  897. end
  898. else
  899. { only offset, can be generated by absolute }
  900. a_load_const_reg(list, OS_ADDR, href.offset, r);
  901. end
  902. else
  903. internalerror(200703111);
  904. end;
  905. procedure TCGMIPS.a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  906. const
  907. FpuMovInstr: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
  908. ((A_MOV_S, A_CVT_D_S),(A_CVT_S_D,A_MOV_D));
  909. var
  910. instr: taicpu;
  911. begin
  912. if (reg1 <> reg2) or (fromsize<>tosize) then
  913. begin
  914. instr := taicpu.op_reg_reg(fpumovinstr[fromsize,tosize], reg2, reg1);
  915. list.Concat(instr);
  916. { Notify the register allocator that we have written a move instruction so
  917. it can try to eliminate it. }
  918. if (fromsize=tosize) then
  919. add_move_instruction(instr);
  920. end;
  921. end;
  922. procedure TCGMIPS.a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister);
  923. var
  924. href: TReference;
  925. begin
  926. href:=ref;
  927. make_simple_ref_fpu(list,href);
  928. case fromsize of
  929. OS_F32:
  930. list.concat(taicpu.op_reg_ref(A_LWC1,reg,href));
  931. OS_F64:
  932. list.concat(taicpu.op_reg_ref(A_LDC1,reg,href));
  933. else
  934. InternalError(2007042701);
  935. end;
  936. if tosize<>fromsize then
  937. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  938. end;
  939. procedure TCGMIPS.a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference);
  940. var
  941. href: TReference;
  942. begin
  943. if tosize<>fromsize then
  944. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  945. href:=ref;
  946. make_simple_ref_fpu(list,href);
  947. case tosize of
  948. OS_F32:
  949. list.concat(taicpu.op_reg_ref(A_SWC1,reg,href));
  950. OS_F64:
  951. list.concat(taicpu.op_reg_ref(A_SDC1,reg,href));
  952. else
  953. InternalError(2007042702);
  954. end;
  955. end;
  956. procedure TCGMIPS.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  957. const
  958. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  959. begin
  960. if (op in overflowops) and
  961. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  962. a_load_reg_reg(list,OS_32,size,dst,dst);
  963. end;
  964. procedure TCGMIPS.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: tcgint; reg: TRegister);
  965. var
  966. power: longint;
  967. tmpreg1: tregister;
  968. begin
  969. if ((op = OP_MUL) or (op = OP_IMUL)) then
  970. begin
  971. if ispowerof2(a, power) then
  972. begin
  973. { can be done with a shift }
  974. if power < 32 then
  975. begin
  976. list.concat(taicpu.op_reg_reg_const(A_SLL, reg, reg, power));
  977. exit;
  978. end;
  979. end;
  980. end;
  981. if ((op = OP_SUB) or (op = OP_ADD)) then
  982. begin
  983. if (a = 0) then
  984. exit;
  985. end;
  986. if Op in [OP_NEG, OP_NOT] then
  987. internalerror(200306011);
  988. if (a = 0) then
  989. begin
  990. if (Op = OP_IMUL) or (Op = OP_MUL) then
  991. list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0))
  992. else
  993. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), reg, reg, NR_R0))
  994. end
  995. else
  996. begin
  997. if op = OP_IMUL then
  998. begin
  999. tmpreg1 := GetIntRegister(list, OS_INT);
  1000. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1001. list.concat(taicpu.op_reg_reg(A_MULT, reg, tmpreg1));
  1002. list.concat(taicpu.op_reg(A_MFLO, reg));
  1003. end
  1004. else if op = OP_MUL then
  1005. begin
  1006. tmpreg1 := GetIntRegister(list, OS_INT);
  1007. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1008. list.concat(taicpu.op_reg_reg(A_MULTU, reg, tmpreg1));
  1009. list.concat(taicpu.op_reg(A_MFLO, reg));
  1010. end
  1011. else
  1012. handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), reg, a, reg);
  1013. end;
  1014. maybeadjustresult(list,op,size,reg);
  1015. end;
  1016. procedure TCGMIPS.a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  1017. var
  1018. a: aint;
  1019. begin
  1020. case Op of
  1021. OP_NEG:
  1022. { discard overflow checking }
  1023. list.concat(taicpu.op_reg_reg(A_NEGU{A_NEG}, dst, src));
  1024. OP_NOT:
  1025. begin
  1026. list.concat(taicpu.op_reg_reg(A_NOT, dst, src));
  1027. end;
  1028. else
  1029. begin
  1030. if op = OP_IMUL then
  1031. begin
  1032. list.concat(taicpu.op_reg_reg(A_MULT, dst, src));
  1033. list.concat(taicpu.op_reg(A_MFLO, dst));
  1034. end
  1035. else if op = OP_MUL then
  1036. begin
  1037. list.concat(taicpu.op_reg_reg(A_MULTU, dst, src));
  1038. list.concat(taicpu.op_reg(A_MFLO, dst));
  1039. end
  1040. else
  1041. begin
  1042. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, dst, src));
  1043. end;
  1044. end;
  1045. end;
  1046. maybeadjustresult(list,op,size,dst);
  1047. end;
  1048. procedure TCGMIPS.a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  1049. var
  1050. power: longint;
  1051. tmpreg1: tregister;
  1052. begin
  1053. case op of
  1054. OP_MUL,
  1055. OP_IMUL:
  1056. begin
  1057. if ispowerof2(a, power) then
  1058. begin
  1059. { can be done with a shift }
  1060. if power < 32 then
  1061. list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src, power))
  1062. else
  1063. inherited a_op_const_reg_reg(list, op, size, a, src, dst);
  1064. exit;
  1065. end;
  1066. end;
  1067. OP_SUB,
  1068. OP_ADD:
  1069. begin
  1070. if (a = 0) then
  1071. begin
  1072. a_load_reg_reg(list, size, size, src, dst);
  1073. exit;
  1074. end;
  1075. end;
  1076. end;
  1077. if op = OP_IMUL then
  1078. begin
  1079. tmpreg1 := GetIntRegister(list, OS_INT);
  1080. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1081. list.concat(taicpu.op_reg_reg(A_MULT, src, tmpreg1));
  1082. list.concat(taicpu.op_reg(A_MFLO, dst));
  1083. end
  1084. else if op = OP_MUL then
  1085. begin
  1086. tmpreg1 := GetIntRegister(list, OS_INT);
  1087. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1088. list.concat(taicpu.op_reg_reg(A_MULTU, src, tmpreg1));
  1089. list.concat(taicpu.op_reg(A_MFLO, dst));
  1090. end
  1091. else
  1092. handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
  1093. maybeadjustresult(list,op,size,dst);
  1094. end;
  1095. procedure TCGMIPS.a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  1096. begin
  1097. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1));
  1098. maybeadjustresult(list,op,size,dst);
  1099. end;
  1100. procedure TCGMIPS.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1101. var
  1102. tmpreg1: tregister;
  1103. begin
  1104. ovloc.loc := LOC_VOID;
  1105. case op of
  1106. OP_SUB,
  1107. OP_ADD:
  1108. begin
  1109. if (a = 0) then
  1110. begin
  1111. a_load_reg_reg(list, size, size, src, dst);
  1112. exit;
  1113. end;
  1114. end;
  1115. end;{case}
  1116. case op of
  1117. OP_ADD:
  1118. begin
  1119. if setflags then
  1120. handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
  1121. else
  1122. handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
  1123. end;
  1124. OP_SUB:
  1125. begin
  1126. if setflags then
  1127. handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
  1128. else
  1129. handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst);
  1130. end;
  1131. OP_MUL:
  1132. begin
  1133. if setflags then
  1134. handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
  1135. else
  1136. begin
  1137. tmpreg1 := GetIntRegister(list, OS_INT);
  1138. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1139. list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1));
  1140. list.concat(taicpu.op_reg(A_MFLO, dst));
  1141. end;
  1142. end;
  1143. OP_IMUL:
  1144. begin
  1145. if setflags then
  1146. handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst)
  1147. else
  1148. begin
  1149. tmpreg1 := GetIntRegister(list, OS_INT);
  1150. a_load_const_reg(list, OS_INT, a, tmpreg1);
  1151. list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1));
  1152. list.concat(taicpu.op_reg(A_MFLO, dst));
  1153. end;
  1154. end;
  1155. OP_XOR, OP_OR, OP_AND:
  1156. begin
  1157. handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst);
  1158. end;
  1159. else
  1160. internalerror(2007012601);
  1161. end;
  1162. maybeadjustresult(list,op,size,dst);
  1163. end;
  1164. procedure TCGMIPS.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1165. begin
  1166. ovloc.loc := LOC_VOID;
  1167. case op of
  1168. OP_ADD:
  1169. begin
  1170. if setflags then
  1171. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
  1172. else
  1173. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1));
  1174. end;
  1175. OP_SUB:
  1176. begin
  1177. if setflags then
  1178. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
  1179. else
  1180. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1));
  1181. end;
  1182. OP_MUL:
  1183. begin
  1184. if setflags then
  1185. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
  1186. else
  1187. begin
  1188. list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1));
  1189. list.concat(taicpu.op_reg(A_MFLO, dst));
  1190. end;
  1191. end;
  1192. OP_IMUL:
  1193. begin
  1194. if setflags then
  1195. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1))
  1196. else
  1197. begin
  1198. list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1));
  1199. list.concat(taicpu.op_reg(A_MFLO, dst));
  1200. end;
  1201. end;
  1202. OP_XOR, OP_OR, OP_AND:
  1203. begin
  1204. list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1));
  1205. end;
  1206. else
  1207. internalerror(2007012602);
  1208. end;
  1209. maybeadjustresult(list,op,size,dst);
  1210. end;
  1211. {*************** compare instructructions ****************}
  1212. procedure TCGMIPS.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1213. var
  1214. tmpreg: tregister;
  1215. ai : Taicpu;
  1216. begin
  1217. if a = 0 then
  1218. tmpreg := NR_R0
  1219. else
  1220. begin
  1221. tmpreg := GetIntRegister(list, OS_INT);
  1222. list.concat(taicpu.op_reg_const(A_LI, tmpreg, a));
  1223. end;
  1224. ai := taicpu.op_reg_reg_sym(A_BC, reg, tmpreg, l);
  1225. ai.SetCondition(TOpCmp2AsmCond[cmp_op]);
  1226. list.concat(ai);
  1227. { Delay slot }
  1228. list.Concat(TAiCpu.Op_none(A_NOP));
  1229. end;
  1230. procedure TCGMIPS.a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  1231. var
  1232. ai : Taicpu;
  1233. begin
  1234. ai := taicpu.op_reg_reg_sym(A_BC, reg2, reg1, l);
  1235. ai.SetCondition(TOpCmp2AsmCond[cmp_op]);
  1236. list.concat(ai);
  1237. { Delay slot }
  1238. list.Concat(TAiCpu.Op_none(A_NOP));
  1239. end;
  1240. procedure TCGMIPS.a_jmp_always(List: tasmlist; l: TAsmLabel);
  1241. var
  1242. ai : Taicpu;
  1243. begin
  1244. ai := taicpu.op_sym(A_BA, l);
  1245. list.concat(ai);
  1246. { Delay slot }
  1247. list.Concat(TAiCpu.Op_none(A_NOP));
  1248. end;
  1249. procedure TCGMIPS.a_jmp_name(list: tasmlist; const s: string);
  1250. begin
  1251. List.Concat(TAiCpu.op_sym(A_BA, current_asmdata.RefAsmSymbol(s)));
  1252. { Delay slot }
  1253. list.Concat(TAiCpu.Op_none(A_NOP));
  1254. end;
  1255. procedure TCGMIPS.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef);
  1256. begin
  1257. // this is an empty procedure
  1258. end;
  1259. procedure TCGMIPS.g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation);
  1260. begin
  1261. // this is an empty procedure
  1262. end;
  1263. { *********** entry/exit code and address loading ************ }
  1264. procedure TCGMIPS.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean);
  1265. var
  1266. lastintoffset,lastfpuoffset,
  1267. nextoffset : aint;
  1268. i : longint;
  1269. ra_save,framesave,gp_save : taicpu;
  1270. fmask,mask : dword;
  1271. saveregs : tcpuregisterset;
  1272. href: treference;
  1273. reg : Tsuperregister;
  1274. helplist : TAsmList;
  1275. begin
  1276. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1277. if nostackframe then
  1278. exit;
  1279. if (TMIPSProcinfo(current_procinfo).needs_frame_pointer) or (pi_needs_stackframe in current_procinfo.flags) then
  1280. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1281. helplist:=TAsmList.Create;
  1282. reference_reset(href,0);
  1283. href.base:=NR_STACK_POINTER_REG;
  1284. fmask:=0;
  1285. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1286. lastfpuoffset:=LocalSize;
  1287. for reg := RS_F0 to RS_F31 do { to check: what if F30 is double? }
  1288. begin
  1289. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1290. begin
  1291. fmask:=fmask or (1 shl ord(reg));
  1292. href.offset:=nextoffset;
  1293. lastfpuoffset:=nextoffset;
  1294. helplist.concat(taicpu.op_reg_ref(A_SWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1295. inc(nextoffset,4);
  1296. { IEEE Double values are stored in floating point
  1297. register pairs f2X/f2X+1,
  1298. as the f2X+1 register is not correctly marked as used for now,
  1299. we simply assume it is also used if f2X is used
  1300. Should be fixed by a proper inclusion of f2X+1 into used_in_proc }
  1301. if (ord(reg)-ord(RS_F0)) mod 2 = 0 then
  1302. include(rg[R_FPUREGISTER].used_in_proc,succ(reg));
  1303. end;
  1304. end;
  1305. mask:=0;
  1306. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1307. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1308. include(saveregs,RS_R31);
  1309. if (TMIPSProcinfo(current_procinfo).needs_frame_pointer) or (pi_needs_stackframe in current_procinfo.flags) then
  1310. include(saveregs,RS_FRAME_POINTER_REG);
  1311. if (cs_create_pic in current_settings.moduleswitches) and
  1312. (pi_needs_got in current_procinfo.flags) then
  1313. include(saveregs,RS_GP);
  1314. lastintoffset:=LocalSize;
  1315. framesave:=nil;
  1316. gp_save:=nil;
  1317. ra_save:=nil;
  1318. for reg:=RS_R1 to RS_R31 do
  1319. begin
  1320. if reg in saveregs then
  1321. begin
  1322. mask:=mask or (1 shl ord(reg));
  1323. href.offset:=nextoffset;
  1324. lastintoffset:=nextoffset;
  1325. if (reg=RS_FRAME_POINTER_REG) then
  1326. framesave:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1327. else if (reg=RS_R31) then
  1328. ra_save:=taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href)
  1329. else if (reg=RS_GP) and
  1330. (cs_create_pic in current_settings.moduleswitches) and
  1331. (pi_needs_got in current_procinfo.flags) then
  1332. gp_save:=taicpu.op_const(A_P_CPRESTORE,nextoffset)
  1333. else
  1334. helplist.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1335. inc(nextoffset,4);
  1336. end;
  1337. end;
  1338. //list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,current_procinfo.para_stack_size));
  1339. list.concat(Taicpu.op_none(A_P_SET_NOMIPS16));
  1340. list.concat(Taicpu.op_reg_const_reg(A_P_FRAME,current_procinfo.framepointer,LocalSize,NR_R31));
  1341. list.concat(Taicpu.op_const_const(A_P_MASK,mask,-(LocalSize-lastintoffset)));
  1342. list.concat(Taicpu.op_const_const(A_P_FMASK,Fmask,-(LocalSize-lastfpuoffset)));
  1343. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1344. if (cs_create_pic in current_settings.moduleswitches) and
  1345. (pi_needs_got in current_procinfo.flags) then
  1346. begin
  1347. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1348. end;
  1349. if (-LocalSize >= simm16lo) and (-LocalSize <= simm16hi) then
  1350. begin
  1351. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1352. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-LocalSize));
  1353. if assigned(ra_save) then
  1354. list.concat(ra_save);
  1355. if assigned(framesave) then
  1356. begin
  1357. list.concat(framesave);
  1358. list.concat(Taicpu.op_reg_reg_const(A_ADDIU,NR_FRAME_POINTER_REG,
  1359. NR_STACK_POINTER_REG,LocalSize));
  1360. end;
  1361. end
  1362. else
  1363. begin
  1364. list.concat(Taicpu.Op_reg_const(A_LI,NR_R9,-LocalSize));
  1365. list.concat(Taicpu.Op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R9));
  1366. if assigned(ra_save) then
  1367. list.concat(ra_save);
  1368. if assigned(framesave) then
  1369. begin
  1370. list.concat(framesave);
  1371. list.concat(Taicpu.op_reg_reg_reg(A_SUBU,NR_FRAME_POINTER_REG,
  1372. NR_STACK_POINTER_REG,NR_R9));
  1373. end;
  1374. { The instructions before are macros that can extend to multiple instructions,
  1375. the settings of R9 to -LocalSize surely does,
  1376. but the saving of RA and FP also might, and might
  1377. even use AT register, which is why we use R9 instead of AT here for -LocalSize }
  1378. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1379. end;
  1380. if assigned(gp_save) then
  1381. begin
  1382. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1383. list.concat(gp_save);
  1384. list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
  1385. end;
  1386. with TMIPSProcInfo(current_procinfo) do
  1387. begin
  1388. href.offset:=0;
  1389. //if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1390. href.base:=NR_FRAME_POINTER_REG;
  1391. for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
  1392. if (register_used[i]) then
  1393. begin
  1394. reg:=parasupregs[i];
  1395. if register_offset[i]=-1 then
  1396. comment(V_warning,'Register parameter has offset -1 in TCGMIPS.g_proc_entry');
  1397. //if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1398. // href.offset:=register_offset[i]+Localsize
  1399. //else
  1400. href.offset:=register_offset[i];
  1401. list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
  1402. end;
  1403. end;
  1404. if (cs_create_pic in current_settings.moduleswitches) and
  1405. (pi_needs_got in current_procinfo.flags) then
  1406. begin
  1407. current_procinfo.got := NR_GP;
  1408. end;
  1409. list.concatList(helplist);
  1410. helplist.Free;
  1411. end;
  1412. procedure TCGMIPS.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean);
  1413. var
  1414. href : treference;
  1415. stacksize : aint;
  1416. saveregs : tcpuregisterset;
  1417. nextoffset : aint;
  1418. reg : Tsuperregister;
  1419. begin
  1420. stacksize:=current_procinfo.calc_stackframe_size;
  1421. if nostackframe then
  1422. begin
  1423. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1424. list.concat(Taicpu.op_none(A_NOP));
  1425. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1426. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1427. end
  1428. else
  1429. begin
  1430. reference_reset(href,0);
  1431. href.base:=NR_STACK_POINTER_REG;
  1432. nextoffset:=TMIPSProcInfo(current_procinfo).floatregstart;
  1433. for reg := RS_F0 to RS_F31 do
  1434. begin
  1435. if reg in (rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall)) then
  1436. begin
  1437. href.offset:=nextoffset;
  1438. list.concat(taicpu.op_reg_ref(A_LWC1,newreg(R_FPUREGISTER,reg,R_SUBFS),href));
  1439. inc(nextoffset,4);
  1440. end;
  1441. end;
  1442. nextoffset:=TMIPSProcInfo(current_procinfo).intregstart;
  1443. saveregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1444. include(saveregs,RS_R31);
  1445. if (TMIPSProcinfo(current_procinfo).needs_frame_pointer) or (pi_needs_stackframe in current_procinfo.flags) then
  1446. include(saveregs,RS_FRAME_POINTER_REG);
  1447. if (cs_create_pic in current_settings.moduleswitches) and
  1448. (pi_needs_got in current_procinfo.flags) then
  1449. include(saveregs,RS_GP);
  1450. for reg:=RS_R1 to RS_R31 do
  1451. begin
  1452. if reg in saveregs then
  1453. begin
  1454. href.offset:=nextoffset;
  1455. list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,reg,R_SUBWHOLE),href));
  1456. inc(nextoffset,sizeof(aint));
  1457. end;
  1458. end;
  1459. if (-stacksize >= simm16lo) and (-stacksize <= simm16hi) then
  1460. begin
  1461. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1462. { correct stack pointer in the delay slot }
  1463. list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, stacksize));
  1464. end
  1465. else
  1466. begin
  1467. a_load_const_reg(list,OS_32,stacksize,NR_R1);
  1468. list.concat(taicpu.op_reg(A_JR, NR_R31));
  1469. { correct stack pointer in the delay slot }
  1470. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R1));
  1471. end;
  1472. list.concat(Taicpu.op_none(A_P_SET_MACRO));
  1473. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1474. end;
  1475. end;
  1476. { ************* concatcopy ************ }
  1477. procedure TCGMIPS.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
  1478. var
  1479. paraloc1, paraloc2, paraloc3: TCGPara;
  1480. pd: tprocdef;
  1481. begin
  1482. pd:=search_system_proc('MOVE');
  1483. paraloc1.init;
  1484. paraloc2.init;
  1485. paraloc3.init;
  1486. paramanager.getintparaloc(pd, 1, paraloc1);
  1487. paramanager.getintparaloc(pd, 2, paraloc2);
  1488. paramanager.getintparaloc(pd, 3, paraloc3);
  1489. a_load_const_cgpara(list, OS_SINT, len, paraloc3);
  1490. a_loadaddr_ref_cgpara(list, dest, paraloc2);
  1491. a_loadaddr_ref_cgpara(list, Source, paraloc1);
  1492. paramanager.freecgpara(list, paraloc3);
  1493. paramanager.freecgpara(list, paraloc2);
  1494. paramanager.freecgpara(list, paraloc1);
  1495. alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1496. alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1497. a_call_name(list, 'FPC_MOVE', false);
  1498. dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
  1499. dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
  1500. paraloc3.done;
  1501. paraloc2.done;
  1502. paraloc1.done;
  1503. end;
  1504. procedure TCGMIPS.g_concatcopy(list: tasmlist; const Source, dest: treference; len: tcgint);
  1505. var
  1506. tmpreg1, hreg, countreg: TRegister;
  1507. src, dst: TReference;
  1508. lab: tasmlabel;
  1509. Count, count2: aint;
  1510. ai : TaiCpu;
  1511. function reference_is_reusable(const ref: treference): boolean;
  1512. begin
  1513. result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
  1514. (ref.symbol=nil) and
  1515. (ref.alignment>=sizeof(aint)) and
  1516. (ref.offset>=simm16lo) and (ref.offset+len<=simm16hi);
  1517. end;
  1518. begin
  1519. if len > high(longint) then
  1520. internalerror(2002072704);
  1521. { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
  1522. allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
  1523. i.e. before secondpass. Other internal procedures request correct stack frame
  1524. by setting pi_do_call during firstpass, but for this particular one it is impossible.
  1525. Therefore, if the current procedure is a leaf one, we have to leave it that way. }
  1526. { anybody wants to determine a good value here :)? }
  1527. if (len > 100) and
  1528. assigned(current_procinfo) and
  1529. (pi_do_call in current_procinfo.flags) then
  1530. g_concatcopy_move(list, Source, dest, len)
  1531. else
  1532. begin
  1533. Count := len div 4;
  1534. if (count<=4) and reference_is_reusable(source) then
  1535. src:=source
  1536. else
  1537. begin
  1538. reference_reset(src,sizeof(aint));
  1539. { load the address of source into src.base }
  1540. src.base := GetAddressRegister(list);
  1541. a_loadaddr_ref_reg(list, Source, src.base);
  1542. end;
  1543. if (count<=4) and reference_is_reusable(dest) then
  1544. dst:=dest
  1545. else
  1546. begin
  1547. reference_reset(dst,sizeof(aint));
  1548. { load the address of dest into dst.base }
  1549. dst.base := GetAddressRegister(list);
  1550. a_loadaddr_ref_reg(list, dest, dst.base);
  1551. end;
  1552. { generate a loop }
  1553. if Count > 4 then
  1554. begin
  1555. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1556. { have to be set to 8. I put an Inc there so debugging may be }
  1557. { easier (should offset be different from zero here, it will be }
  1558. { easy to notice in the generated assembler }
  1559. countreg := GetIntRegister(list, OS_INT);
  1560. tmpreg1 := GetIntRegister(list, OS_INT);
  1561. a_load_const_reg(list, OS_INT, Count, countreg);
  1562. { explicitely allocate R_O0 since it can be used safely here }
  1563. { (for holding date that's being copied) }
  1564. current_asmdata.getjumplabel(lab);
  1565. a_label(list, lab);
  1566. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1567. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1568. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4));
  1569. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4));
  1570. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1571. //list.concat(taicpu.op_reg_sym(A_BGTZ, countreg, lab));
  1572. ai := taicpu.op_reg_reg_sym(A_BC,countreg, NR_R0, lab);
  1573. ai.setcondition(C_GT);
  1574. list.concat(ai);
  1575. list.concat(taicpu.op_none(A_NOP));
  1576. len := len mod 4;
  1577. end;
  1578. { unrolled loop }
  1579. Count := len div 4;
  1580. if Count > 0 then
  1581. begin
  1582. tmpreg1 := GetIntRegister(list, OS_INT);
  1583. for count2 := 1 to Count do
  1584. begin
  1585. list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
  1586. list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
  1587. Inc(src.offset, 4);
  1588. Inc(dst.offset, 4);
  1589. end;
  1590. len := len mod 4;
  1591. end;
  1592. if (len and 4) <> 0 then
  1593. begin
  1594. hreg := GetIntRegister(list, OS_INT);
  1595. a_load_ref_reg(list, OS_32, OS_32, src, hreg);
  1596. a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
  1597. Inc(src.offset, 4);
  1598. Inc(dst.offset, 4);
  1599. end;
  1600. { copy the leftovers }
  1601. if (len and 2) <> 0 then
  1602. begin
  1603. hreg := GetIntRegister(list, OS_INT);
  1604. a_load_ref_reg(list, OS_16, OS_16, src, hreg);
  1605. a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
  1606. Inc(src.offset, 2);
  1607. Inc(dst.offset, 2);
  1608. end;
  1609. if (len and 1) <> 0 then
  1610. begin
  1611. hreg := GetIntRegister(list, OS_INT);
  1612. a_load_ref_reg(list, OS_8, OS_8, src, hreg);
  1613. a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
  1614. end;
  1615. end;
  1616. end;
  1617. procedure TCGMIPS.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: tcgint);
  1618. var
  1619. src, dst: TReference;
  1620. tmpreg1, countreg: TRegister;
  1621. i: aint;
  1622. lab: tasmlabel;
  1623. ai : TaiCpu;
  1624. begin
  1625. if (len > 31) and
  1626. { see comment in g_concatcopy }
  1627. assigned(current_procinfo) and
  1628. (pi_do_call in current_procinfo.flags) then
  1629. g_concatcopy_move(list, Source, dest, len)
  1630. else
  1631. begin
  1632. reference_reset(src,sizeof(aint));
  1633. reference_reset(dst,sizeof(aint));
  1634. { load the address of source into src.base }
  1635. src.base := GetAddressRegister(list);
  1636. a_loadaddr_ref_reg(list, Source, src.base);
  1637. { load the address of dest into dst.base }
  1638. dst.base := GetAddressRegister(list);
  1639. a_loadaddr_ref_reg(list, dest, dst.base);
  1640. { generate a loop }
  1641. if len > 4 then
  1642. begin
  1643. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1644. { have to be set to 8. I put an Inc there so debugging may be }
  1645. { easier (should offset be different from zero here, it will be }
  1646. { easy to notice in the generated assembler }
  1647. countreg := cg.GetIntRegister(list, OS_INT);
  1648. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1649. a_load_const_reg(list, OS_INT, len, countreg);
  1650. { explicitely allocate R_O0 since it can be used safely here }
  1651. { (for holding date that's being copied) }
  1652. current_asmdata.getjumplabel(lab);
  1653. a_label(list, lab);
  1654. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1655. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1656. list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1));
  1657. list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1));
  1658. list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1));
  1659. //list.concat(taicpu.op_reg_sym(A_BGTZ, countreg, lab));
  1660. ai := taicpu.op_reg_reg_sym(A_BC,countreg, NR_R0, lab);
  1661. ai.setcondition(C_GT);
  1662. list.concat(ai);
  1663. list.concat(taicpu.op_none(A_NOP));
  1664. end
  1665. else
  1666. begin
  1667. { unrolled loop }
  1668. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1669. for i := 1 to len do
  1670. begin
  1671. list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src));
  1672. list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst));
  1673. Inc(src.offset);
  1674. Inc(dst.offset);
  1675. end;
  1676. end;
  1677. end;
  1678. end;
  1679. procedure TCGMIPS.g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint);
  1680. var
  1681. make_global: boolean;
  1682. hsym: tsym;
  1683. href: treference;
  1684. paraloc: Pcgparalocation;
  1685. IsVirtual: boolean;
  1686. begin
  1687. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1688. Internalerror(200006137);
  1689. if not assigned(procdef.struct) or
  1690. (procdef.procoptions * [po_classmethod, po_staticmethod,
  1691. po_methodpointer, po_interrupt, po_iocheck] <> []) then
  1692. Internalerror(200006138);
  1693. if procdef.owner.symtabletype <> objectsymtable then
  1694. Internalerror(200109191);
  1695. make_global := False;
  1696. if (not current_module.is_unit) or create_smartlink or
  1697. (procdef.owner.defowner.owner.symtabletype = globalsymtable) then
  1698. make_global := True;
  1699. if make_global then
  1700. List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0))
  1701. else
  1702. List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0));
  1703. IsVirtual:=(po_virtualmethod in procdef.procoptions) and
  1704. not is_objectpascal_helper(procdef.struct);
  1705. if (cs_create_pic in current_settings.moduleswitches) and
  1706. (not IsVirtual) then
  1707. begin
  1708. list.concat(Taicpu.op_none(A_P_SET_NOREORDER));
  1709. list.concat(Taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1710. list.concat(Taicpu.op_none(A_P_SET_REORDER));
  1711. end;
  1712. { set param1 interface to self }
  1713. procdef.init_paraloc_info(callerside);
  1714. hsym:=tsym(procdef.parast.Find('self'));
  1715. if not(assigned(hsym) and
  1716. (hsym.typ=paravarsym)) then
  1717. internalerror(2010103101);
  1718. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1719. if assigned(paraloc^.next) then
  1720. InternalError(2013020101);
  1721. case paraloc^.loc of
  1722. LOC_REGISTER:
  1723. begin
  1724. if ((ioffset>=simm16lo) and (ioffset<=simm16hi)) then
  1725. a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
  1726. else
  1727. begin
  1728. a_load_const_reg(list, paraloc^.size, ioffset, NR_R1);
  1729. a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_R1, paraloc^.register);
  1730. end;
  1731. end;
  1732. else
  1733. internalerror(2010103102);
  1734. end;
  1735. if IsVirtual then
  1736. begin
  1737. { load VMT pointer }
  1738. reference_reset_base(href,paraloc^.register,0,sizeof(aint));
  1739. list.concat(taicpu.op_reg_ref(A_LW,NR_VMT,href));
  1740. if (procdef.extnumber=$ffff) then
  1741. Internalerror(200006139);
  1742. { TODO: case of large VMT is not handled }
  1743. { We have no reason not to use $t9 even in non-PIC mode. }
  1744. reference_reset_base(href, NR_VMT, tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber), sizeof(aint));
  1745. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1746. list.concat(taicpu.op_reg(A_JR, NR_PIC_FUNC));
  1747. end
  1748. else if not (cs_create_pic in current_settings.moduleswitches) then
  1749. list.concat(taicpu.op_sym(A_J,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  1750. else
  1751. begin
  1752. { GAS does not expand "J symbol" into PIC sequence }
  1753. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0,sizeof(pint));
  1754. href.base:=NR_GP;
  1755. href.refaddr:=addr_pic_call16;
  1756. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1757. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1758. end;
  1759. { Delay slot }
  1760. list.Concat(TAiCpu.Op_none(A_NOP));
  1761. List.concat(Tai_symbol_end.Createname(labelname));
  1762. end;
  1763. procedure TCGMIPS.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  1764. var
  1765. href: treference;
  1766. begin
  1767. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname),0,sizeof(aint));
  1768. { Always do indirect jump using $t9, it won't harm in non-PIC mode }
  1769. if (cs_create_pic in current_settings.moduleswitches) then
  1770. begin
  1771. list.concat(taicpu.op_none(A_P_SET_NOREORDER));
  1772. list.concat(taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
  1773. href.base:=NR_GP;
  1774. href.refaddr:=addr_pic_call16;
  1775. list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
  1776. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1777. { Delay slot }
  1778. list.Concat(taicpu.op_none(A_NOP));
  1779. list.Concat(taicpu.op_none(A_P_SET_REORDER));
  1780. end
  1781. else
  1782. begin
  1783. href.refaddr:=addr_high;
  1784. list.concat(taicpu.op_reg_ref(A_LUI,NR_PIC_FUNC,href));
  1785. href.refaddr:=addr_low;
  1786. list.concat(taicpu.op_reg_ref(A_ADDIU,NR_PIC_FUNC,href));
  1787. list.concat(taicpu.op_reg(A_JR,NR_PIC_FUNC));
  1788. { Delay slot }
  1789. list.Concat(taicpu.op_none(A_NOP));
  1790. end;
  1791. end;
  1792. procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1793. begin
  1794. { This method is integrated into g_intf_wrapper and shouldn't be called separately }
  1795. InternalError(2013020102);
  1796. end;
  1797. procedure TCGMIPS.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1798. begin
  1799. Comment(V_Error,'TCgMPSel.g_stackpointer_alloc method not implemented');
  1800. end;
  1801. procedure TCGMIPS.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1802. begin
  1803. Comment(V_Error,'TCgMPSel.a_bit_scan_reg_reg method not implemented');
  1804. end;
  1805. {****************************************************************************
  1806. TCG64_MIPSel
  1807. ****************************************************************************}
  1808. procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference);
  1809. var
  1810. tmpref: treference;
  1811. tmpreg: tregister;
  1812. begin
  1813. { Override this function to prevent loading the reference twice }
  1814. if target_info.endian = endian_big then
  1815. begin
  1816. tmpreg := reg.reglo;
  1817. reg.reglo := reg.reghi;
  1818. reg.reghi := tmpreg;
  1819. end;
  1820. tmpref := ref;
  1821. cg.a_load_reg_ref(list, OS_S32, OS_S32, reg.reglo, tmpref);
  1822. Inc(tmpref.offset, 4);
  1823. cg.a_load_reg_ref(list, OS_S32, OS_S32, reg.reghi, tmpref);
  1824. end;
  1825. procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64);
  1826. var
  1827. tmpref: treference;
  1828. tmpreg: tregister;
  1829. begin
  1830. { Override this function to prevent loading the reference twice }
  1831. if target_info.endian = endian_big then
  1832. begin
  1833. tmpreg := reg.reglo;
  1834. reg.reglo := reg.reghi;
  1835. reg.reghi := tmpreg;
  1836. end;
  1837. tmpref := ref;
  1838. cg.a_load_ref_reg(list, OS_S32, OS_S32, tmpref, reg.reglo);
  1839. Inc(tmpref.offset, 4);
  1840. cg.a_load_ref_reg(list, OS_S32, OS_S32, tmpref, reg.reghi);
  1841. end;
  1842. procedure TCg64MPSel.a_load64_ref_cgpara(list: tasmlist; const r: treference; const paraloc: tcgpara);
  1843. var
  1844. hreg64: tregister64;
  1845. begin
  1846. { Override this function to prevent loading the reference twice.
  1847. Use here some extra registers, but those are optimized away by the RA }
  1848. hreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1849. hreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1850. a_load64_ref_reg(list, r, hreg64);
  1851. a_load64_reg_cgpara(list, hreg64, paraloc);
  1852. end;
  1853. procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64);
  1854. var
  1855. op1, op2, op_call64: TAsmOp;
  1856. tmpreg1, tmpreg2: TRegister;
  1857. begin
  1858. tmpreg1 := cg.GetIntRegister(list, OS_INT);
  1859. tmpreg2 := cg.GetIntRegister(list, OS_INT);
  1860. case op of
  1861. OP_ADD:
  1862. begin
  1863. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reglo, regsrc.reglo, regdst.reglo));
  1864. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, regdst.reglo, regsrc.reglo));
  1865. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg2, regsrc.reghi, regdst.reghi));
  1866. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, tmpreg1, tmpreg2));
  1867. exit;
  1868. end;
  1869. OP_AND:
  1870. begin
  1871. list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reglo, regsrc.reglo, regdst.reglo));
  1872. list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reghi, regsrc.reghi, regdst.reghi));
  1873. exit;
  1874. end;
  1875. OP_NEG:
  1876. begin
  1877. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo));
  1878. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_R0, regdst.reglo));
  1879. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi));
  1880. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg1));
  1881. exit;
  1882. end;
  1883. OP_NOT:
  1884. begin
  1885. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo));
  1886. list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi));
  1887. exit;
  1888. end;
  1889. OP_OR:
  1890. begin
  1891. list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reglo, regsrc.reglo, regdst.reglo));
  1892. list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reghi, regsrc.reghi, regdst.reghi));
  1893. exit;
  1894. end;
  1895. OP_SUB:
  1896. begin
  1897. list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg1, regdst.reglo, regsrc.reglo));
  1898. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg2, regdst.reglo, tmpreg1));
  1899. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, regsrc.reghi));
  1900. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg2));
  1901. list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reglo, tmpreg1));
  1902. exit;
  1903. end;
  1904. OP_XOR:
  1905. begin
  1906. list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reglo, regdst.reglo, regsrc.reglo));
  1907. list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reghi, regsrc.reghi, regdst.reghi));
  1908. exit;
  1909. end;
  1910. else
  1911. internalerror(200306017);
  1912. end; {case}
  1913. end;
  1914. procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64);
  1915. begin
  1916. a_op64_const_reg_reg(list, op, size, value, regdst, regdst);
  1917. end;
  1918. procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64);
  1919. var
  1920. l: tlocation;
  1921. begin
  1922. a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l);
  1923. end;
  1924. procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64);
  1925. var
  1926. l: tlocation;
  1927. begin
  1928. a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l);
  1929. end;
  1930. procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1931. var
  1932. tmpreg64: TRegister64;
  1933. begin
  1934. tmpreg64.reglo := cg.GetIntRegister(list, OS_S32);
  1935. tmpreg64.reghi := cg.GetIntRegister(list, OS_S32);
  1936. list.concat(taicpu.op_reg_const(A_LI, tmpreg64.reglo, aint(lo(Value))));
  1937. list.concat(taicpu.op_reg_const(A_LI, tmpreg64.reghi, aint(hi(Value))));
  1938. a_op64_reg_reg_reg_checkoverflow(list, op, size, tmpreg64, regsrc, regdst, False, ovloc);
  1939. end;
  1940. procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation);
  1941. var
  1942. op1, op2: TAsmOp;
  1943. tmpreg1, tmpreg2: TRegister;
  1944. begin
  1945. case op of
  1946. OP_ADD:
  1947. begin
  1948. tmpreg1 := cg.GetIntRegister(list,OS_S32);
  1949. tmpreg2 := cg.GetIntRegister(list,OS_S32);
  1950. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1951. list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, regsrc2.reglo, regsrc1.reglo));
  1952. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg2, tmpreg1, regsrc2.reglo));
  1953. list.concat(taicpu.op_reg_reg(A_MOVE, regdst.reglo, tmpreg1));
  1954. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1955. list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, regdst.reghi, tmpreg2));
  1956. exit;
  1957. end;
  1958. OP_AND:
  1959. begin
  1960. list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reglo, regsrc2.reglo, regsrc1.reglo));
  1961. list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1962. exit;
  1963. end;
  1964. OP_OR:
  1965. begin
  1966. list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reglo, regsrc2.reglo, regsrc1.reglo));
  1967. list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1968. exit;
  1969. end;
  1970. OP_SUB:
  1971. begin
  1972. tmpreg1 := cg.GetIntRegister(list,OS_S32);
  1973. tmpreg2 := cg.GetIntRegister(list,OS_S32);
  1974. // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
  1975. list.concat(taicpu.op_reg_reg_reg(A_SUBU,tmpreg1, regsrc2.reglo, regsrc1.reglo));
  1976. list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg2, regsrc2.reglo,tmpreg1));
  1977. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1978. list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regdst.reghi, tmpreg2));
  1979. list.concat(taicpu.op_reg_reg(A_MOVE, regdst.reglo, tmpreg1));
  1980. exit;
  1981. end;
  1982. OP_XOR:
  1983. begin
  1984. list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reglo, regsrc2.reglo, regsrc1.reglo));
  1985. list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
  1986. exit;
  1987. end;
  1988. else
  1989. internalerror(200306017);
  1990. end; {case}
  1991. end;
  1992. procedure create_codegen;
  1993. begin
  1994. cg:=TCGMIPS.Create;
  1995. cg64:=TCg64MPSel.Create;
  1996. end;
  1997. end.