cgcpu.pas 77 KB

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