cgcpu.pas 77 KB

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