cgcpu.pas 76 KB

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