cgcpu.pas 77 KB

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