cgcpu.pas 76 KB

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