cgcpu.pas 73 KB

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