cgcpu.pas 78 KB

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