cgcpu.pas 69 KB

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