cgcpu.pas 65 KB

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