cgcpu.pas 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. cgsetflags : boolean;
  31. procedure init_register_allocators;override;
  32. procedure done_register_allocators;override;
  33. procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : TAsmList;const s : string);override;
  37. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  38. procedure a_call_ref(list : TAsmList;ref: treference);override;
  39. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  42. size: tcgsize; a: aint; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  47. { move instructions }
  48. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  49. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  50. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  51. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  52. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  53. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  54. { fpu move instructions }
  55. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  58. procedure a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  59. { comparison operations }
  60. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  61. l : tasmlabel);override;
  62. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  63. procedure a_jmp_name(list : TAsmList;const s : string); override;
  64. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  65. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  67. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  68. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  69. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  70. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
  71. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
  72. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  73. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  74. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  75. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  76. procedure g_save_registers(list : TAsmList);override;
  77. procedure g_restore_registers(list : TAsmList);override;
  78. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  79. procedure fixref(list : TAsmList;var ref : treference);
  80. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  81. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  82. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint); override;
  83. procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
  84. private
  85. { clear out potential overflow bits from 8 or 16 bit operations }
  86. { the upper 24/16 bits of a register after an operation }
  87. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  88. end;
  89. tcg64farm = class(tcg64f32)
  90. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  91. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  92. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  93. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  94. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  95. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  96. end;
  97. const
  98. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  99. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  100. winstackpagesize = 4096;
  101. function get_fpu_postfix(def : tdef) : toppostfix;
  102. implementation
  103. uses
  104. globals,verbose,systems,cutils,
  105. fmodule,
  106. symconst,symsym,
  107. tgobj,
  108. procinfo,cpupi,
  109. paramgr;
  110. function get_fpu_postfix(def : tdef) : toppostfix;
  111. begin
  112. if def.typ=floatdef then
  113. begin
  114. case tfloatdef(def).floattype of
  115. s32real:
  116. result:=PF_S;
  117. s64real:
  118. result:=PF_D;
  119. s80real:
  120. result:=PF_E;
  121. else
  122. internalerror(200401272);
  123. end;
  124. end
  125. else
  126. internalerror(200401271);
  127. end;
  128. procedure tcgarm.init_register_allocators;
  129. begin
  130. inherited init_register_allocators;
  131. { currently, we save R14 always, so we can use it }
  132. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  133. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  134. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  135. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  136. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  137. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  138. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  139. end;
  140. procedure tcgarm.done_register_allocators;
  141. begin
  142. rg[R_INTREGISTER].free;
  143. rg[R_FPUREGISTER].free;
  144. rg[R_MMREGISTER].free;
  145. inherited done_register_allocators;
  146. end;
  147. procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  148. var
  149. ref: treference;
  150. begin
  151. paraloc.check_simple_location;
  152. case paraloc.location^.loc of
  153. LOC_REGISTER,LOC_CREGISTER:
  154. a_load_const_reg(list,size,a,paraloc.location^.register);
  155. LOC_REFERENCE:
  156. begin
  157. reference_reset(ref);
  158. ref.base:=paraloc.location^.reference.index;
  159. ref.offset:=paraloc.location^.reference.offset;
  160. a_load_const_ref(list,size,a,ref);
  161. end;
  162. else
  163. internalerror(2002081101);
  164. end;
  165. end;
  166. procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  167. var
  168. tmpref, ref: treference;
  169. location: pcgparalocation;
  170. sizeleft: aint;
  171. begin
  172. location := paraloc.location;
  173. tmpref := r;
  174. sizeleft := paraloc.intsize;
  175. while assigned(location) do
  176. begin
  177. case location^.loc of
  178. LOC_REGISTER,LOC_CREGISTER:
  179. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  180. LOC_REFERENCE:
  181. begin
  182. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  183. { doubles in softemu mode have a strange order of registers and references }
  184. if location^.size=OS_32 then
  185. g_concatcopy(list,tmpref,ref,4)
  186. else
  187. begin
  188. g_concatcopy(list,tmpref,ref,sizeleft);
  189. if assigned(location^.next) then
  190. internalerror(2005010710);
  191. end;
  192. end;
  193. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  194. case location^.size of
  195. OS_F32, OS_F64:
  196. a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  197. else
  198. internalerror(2002072801);
  199. end;
  200. LOC_VOID:
  201. begin
  202. // nothing to do
  203. end;
  204. else
  205. internalerror(2002081103);
  206. end;
  207. inc(tmpref.offset,tcgsize2size[location^.size]);
  208. dec(sizeleft,tcgsize2size[location^.size]);
  209. location := location^.next;
  210. end;
  211. end;
  212. procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
  213. var
  214. ref: treference;
  215. tmpreg: tregister;
  216. begin
  217. paraloc.check_simple_location;
  218. case paraloc.location^.loc of
  219. LOC_REGISTER,LOC_CREGISTER:
  220. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  221. LOC_REFERENCE:
  222. begin
  223. reference_reset(ref);
  224. ref.base := paraloc.location^.reference.index;
  225. ref.offset := paraloc.location^.reference.offset;
  226. tmpreg := getintregister(list,OS_ADDR);
  227. a_loadaddr_ref_reg(list,r,tmpreg);
  228. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  229. end;
  230. else
  231. internalerror(2002080701);
  232. end;
  233. end;
  234. procedure tcgarm.a_call_name(list : TAsmList;const s : string);
  235. begin
  236. list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)));
  237. {
  238. the compiler does not properly set this flag anymore in pass 1, and
  239. for now we only need it after pass 2 (I hope) (JM)
  240. if not(pi_do_call in current_procinfo.flags) then
  241. internalerror(2003060703);
  242. }
  243. include(current_procinfo.flags,pi_do_call);
  244. end;
  245. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  246. begin
  247. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  248. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  249. {
  250. the compiler does not properly set this flag anymore in pass 1, and
  251. for now we only need it after pass 2 (I hope) (JM)
  252. if not(pi_do_call in current_procinfo.flags) then
  253. internalerror(2003060703);
  254. }
  255. include(current_procinfo.flags,pi_do_call);
  256. end;
  257. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  258. begin
  259. a_reg_alloc(list,NR_R12);
  260. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  261. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  262. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  263. a_reg_dealloc(list,NR_R12);
  264. include(current_procinfo.flags,pi_do_call);
  265. end;
  266. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  267. begin
  268. a_op_const_reg_reg(list,op,size,a,reg,reg);
  269. end;
  270. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  271. begin
  272. case op of
  273. OP_NEG:
  274. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  275. OP_NOT:
  276. begin
  277. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  278. case size of
  279. OS_8 :
  280. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  281. OS_16 :
  282. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  283. end;
  284. end
  285. else
  286. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  287. end;
  288. end;
  289. const
  290. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  291. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  292. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE);
  293. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  294. size: tcgsize; a: aint; src, dst: tregister);
  295. var
  296. ovloc : tlocation;
  297. begin
  298. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  299. end;
  300. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  301. size: tcgsize; src1, src2, dst: tregister);
  302. var
  303. ovloc : tlocation;
  304. begin
  305. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  306. end;
  307. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  308. var
  309. shift : byte;
  310. tmpreg : tregister;
  311. so : tshifterop;
  312. l1 : longint;
  313. begin
  314. ovloc.loc:=LOC_VOID;
  315. if is_shifter_const(-a,shift) then
  316. case op of
  317. OP_ADD:
  318. begin
  319. op:=OP_SUB;
  320. a:=aint(dword(-a));
  321. end;
  322. OP_SUB:
  323. begin
  324. op:=OP_ADD;
  325. a:=aint(dword(-a));
  326. end
  327. end;
  328. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  329. case op of
  330. OP_NEG,OP_NOT,
  331. OP_DIV,OP_IDIV:
  332. internalerror(200308281);
  333. OP_SHL:
  334. begin
  335. if a>32 then
  336. internalerror(200308294);
  337. if a<>0 then
  338. begin
  339. shifterop_reset(so);
  340. so.shiftmode:=SM_LSL;
  341. so.shiftimm:=a;
  342. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  343. end
  344. else
  345. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  346. end;
  347. OP_ROL:
  348. begin
  349. if a>32 then
  350. internalerror(200308294);
  351. if a<>0 then
  352. begin
  353. shifterop_reset(so);
  354. so.shiftmode:=SM_ROR;
  355. so.shiftimm:=32-a;
  356. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  357. end
  358. else
  359. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  360. end;
  361. OP_ROR:
  362. begin
  363. if a>32 then
  364. internalerror(200308294);
  365. if a<>0 then
  366. begin
  367. shifterop_reset(so);
  368. so.shiftmode:=SM_ROR;
  369. so.shiftimm:=a;
  370. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  371. end
  372. else
  373. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  374. end;
  375. OP_SHR:
  376. begin
  377. if a>32 then
  378. internalerror(200308292);
  379. shifterop_reset(so);
  380. if a<>0 then
  381. begin
  382. so.shiftmode:=SM_LSR;
  383. so.shiftimm:=a;
  384. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  385. end
  386. else
  387. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  388. end;
  389. OP_SAR:
  390. begin
  391. if a>32 then
  392. internalerror(200308295);
  393. if a<>0 then
  394. begin
  395. shifterop_reset(so);
  396. so.shiftmode:=SM_ASR;
  397. so.shiftimm:=a;
  398. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  399. end
  400. else
  401. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  402. end;
  403. else
  404. list.concat(setoppostfix(
  405. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  406. ));
  407. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  408. begin
  409. ovloc.loc:=LOC_FLAGS;
  410. case op of
  411. OP_ADD:
  412. ovloc.resflags:=F_CS;
  413. OP_SUB:
  414. ovloc.resflags:=F_CC;
  415. end;
  416. end;
  417. end
  418. else
  419. begin
  420. { there could be added some more sophisticated optimizations }
  421. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  422. a_load_reg_reg(list,size,size,src,dst)
  423. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  424. a_load_const_reg(list,size,0,dst)
  425. else if (op in [OP_IMUL]) and (a=-1) then
  426. a_op_reg_reg(list,OP_NEG,size,src,dst)
  427. { we do this here instead in the peephole optimizer because
  428. it saves us a register }
  429. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  430. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  431. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  432. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  433. begin
  434. if l1>32 then{roozbeh does this ever happen?}
  435. internalerror(200308296);
  436. shifterop_reset(so);
  437. so.shiftmode:=SM_LSL;
  438. so.shiftimm:=l1;
  439. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  440. end
  441. else
  442. begin
  443. tmpreg:=getintregister(list,size);
  444. a_load_const_reg(list,size,a,tmpreg);
  445. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  446. end;
  447. end;
  448. maybeadjustresult(list,op,size,dst);
  449. end;
  450. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  451. var
  452. so : tshifterop;
  453. tmpreg,overflowreg : tregister;
  454. asmop : tasmop;
  455. begin
  456. ovloc.loc:=LOC_VOID;
  457. case op of
  458. OP_NEG,OP_NOT,
  459. OP_DIV,OP_IDIV:
  460. internalerror(200308281);
  461. OP_SHL:
  462. begin
  463. shifterop_reset(so);
  464. so.rs:=src1;
  465. so.shiftmode:=SM_LSL;
  466. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  467. end;
  468. OP_SHR:
  469. begin
  470. shifterop_reset(so);
  471. so.rs:=src1;
  472. so.shiftmode:=SM_LSR;
  473. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  474. end;
  475. OP_SAR:
  476. begin
  477. shifterop_reset(so);
  478. so.rs:=src1;
  479. so.shiftmode:=SM_ASR;
  480. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  481. end;
  482. OP_ROL:
  483. begin
  484. if not(size in [OS_32,OS_S32]) then
  485. internalerror(2008072801);
  486. { simulate ROL by ror'ing 32-value }
  487. tmpreg:=getintregister(list,OS_32);
  488. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  489. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  490. shifterop_reset(so);
  491. so.rs:=src1;
  492. so.shiftmode:=SM_ROR;
  493. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  494. end;
  495. OP_ROR:
  496. begin
  497. if not(size in [OS_32,OS_S32]) then
  498. internalerror(2008072802);
  499. shifterop_reset(so);
  500. so.rs:=src1;
  501. so.shiftmode:=SM_ROR;
  502. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  503. end;
  504. OP_IMUL,
  505. OP_MUL:
  506. begin
  507. if cgsetflags or setflags then
  508. begin
  509. overflowreg:=getintregister(list,size);
  510. if op=OP_IMUL then
  511. asmop:=A_SMULL
  512. else
  513. asmop:=A_UMULL;
  514. { the arm doesn't allow that rd and rm are the same }
  515. if dst=src2 then
  516. begin
  517. if dst<>src1 then
  518. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  519. else
  520. begin
  521. tmpreg:=getintregister(list,size);
  522. a_load_reg_reg(list,size,size,src2,dst);
  523. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  524. end;
  525. end
  526. else
  527. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  528. if op=OP_IMUL then
  529. begin
  530. shifterop_reset(so);
  531. so.shiftmode:=SM_ASR;
  532. so.shiftimm:=31;
  533. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  534. end
  535. else
  536. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  537. ovloc.loc:=LOC_FLAGS;
  538. ovloc.resflags:=F_NE;
  539. end
  540. else
  541. begin
  542. { the arm doesn't allow that rd and rm are the same }
  543. if dst=src2 then
  544. begin
  545. if dst<>src1 then
  546. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  547. else
  548. begin
  549. tmpreg:=getintregister(list,size);
  550. a_load_reg_reg(list,size,size,src2,dst);
  551. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  552. end;
  553. end
  554. else
  555. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  556. end;
  557. end;
  558. else
  559. list.concat(setoppostfix(
  560. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  561. ));
  562. end;
  563. maybeadjustresult(list,op,size,dst);
  564. end;
  565. procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  566. var
  567. imm_shift : byte;
  568. l : tasmlabel;
  569. hr : treference;
  570. begin
  571. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  572. internalerror(2002090902);
  573. if is_shifter_const(a,imm_shift) then
  574. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  575. else if is_shifter_const(not(a),imm_shift) then
  576. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  577. { loading of constants with mov and orr }
  578. else if (is_shifter_const(a-byte(a),imm_shift)) then
  579. begin
  580. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  581. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  582. end
  583. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  584. begin
  585. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  586. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  587. end
  588. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  589. begin
  590. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  591. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  592. end
  593. else
  594. begin
  595. reference_reset(hr);
  596. current_asmdata.getjumplabel(l);
  597. cg.a_label(current_procinfo.aktlocaldata,l);
  598. hr.symboldata:=current_procinfo.aktlocaldata.last;
  599. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  600. hr.symbol:=l;
  601. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  602. end;
  603. end;
  604. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  605. var
  606. tmpreg : tregister;
  607. tmpref : treference;
  608. l : tasmlabel;
  609. begin
  610. tmpreg:=NR_NO;
  611. { Be sure to have a base register }
  612. if (ref.base=NR_NO) then
  613. begin
  614. if ref.shiftmode<>SM_None then
  615. internalerror(200308294);
  616. ref.base:=ref.index;
  617. ref.index:=NR_NO;
  618. end;
  619. { absolute symbols can't be handled directly, we've to store the symbol reference
  620. in the text segment and access it pc relative
  621. For now, we assume that references where base or index equals to PC are already
  622. relative, all other references are assumed to be absolute and thus they need
  623. to be handled extra.
  624. A proper solution would be to change refoptions to a set and store the information
  625. if the symbol is absolute or relative there.
  626. }
  627. if (assigned(ref.symbol) and
  628. not(is_pc(ref.base)) and
  629. not(is_pc(ref.index))
  630. ) or
  631. { [#xxx] isn't a valid address operand }
  632. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  633. (ref.offset<-4095) or
  634. (ref.offset>4095) or
  635. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  636. ((ref.offset<-255) or
  637. (ref.offset>255)
  638. )
  639. ) or
  640. ((op in [A_LDF,A_STF]) and
  641. ((ref.offset<-1020) or
  642. (ref.offset>1020) or
  643. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  644. assigned(ref.symbol)
  645. )
  646. ) then
  647. begin
  648. reference_reset(tmpref);
  649. { load symbol }
  650. tmpreg:=getintregister(list,OS_INT);
  651. if assigned(ref.symbol) then
  652. begin
  653. current_asmdata.getjumplabel(l);
  654. cg.a_label(current_procinfo.aktlocaldata,l);
  655. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  656. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  657. { load consts entry }
  658. tmpref.symbol:=l;
  659. tmpref.base:=NR_R15;
  660. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  661. { in case of LDF/STF, we got rid of the NR_R15 }
  662. if is_pc(ref.base) then
  663. ref.base:=NR_NO;
  664. if is_pc(ref.index) then
  665. ref.index:=NR_NO;
  666. end
  667. else
  668. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  669. if (ref.base<>NR_NO) then
  670. begin
  671. if ref.index<>NR_NO then
  672. begin
  673. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  674. ref.base:=tmpreg;
  675. end
  676. else
  677. begin
  678. ref.index:=tmpreg;
  679. ref.shiftimm:=0;
  680. ref.signindex:=1;
  681. ref.shiftmode:=SM_None;
  682. end;
  683. end
  684. else
  685. ref.base:=tmpreg;
  686. ref.offset:=0;
  687. ref.symbol:=nil;
  688. end;
  689. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  690. begin
  691. if tmpreg<>NR_NO then
  692. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  693. else
  694. begin
  695. tmpreg:=getintregister(list,OS_ADDR);
  696. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  697. ref.base:=tmpreg;
  698. end;
  699. ref.offset:=0;
  700. end;
  701. { floating point operations have only limited references
  702. we expect here, that a base is already set }
  703. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  704. begin
  705. if ref.shiftmode<>SM_none then
  706. internalerror(200309121);
  707. if tmpreg<>NR_NO then
  708. begin
  709. if ref.base=tmpreg then
  710. begin
  711. if ref.signindex<0 then
  712. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  713. else
  714. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  715. ref.index:=NR_NO;
  716. end
  717. else
  718. begin
  719. if ref.index<>tmpreg then
  720. internalerror(200403161);
  721. if ref.signindex<0 then
  722. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  723. else
  724. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  725. ref.base:=tmpreg;
  726. ref.index:=NR_NO;
  727. end;
  728. end
  729. else
  730. begin
  731. tmpreg:=getintregister(list,OS_ADDR);
  732. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  733. ref.base:=tmpreg;
  734. ref.index:=NR_NO;
  735. end;
  736. end;
  737. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  738. Result := ref;
  739. end;
  740. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  741. var
  742. oppostfix:toppostfix;
  743. usedtmpref: treference;
  744. tmpreg : tregister;
  745. so : tshifterop;
  746. dir : integer;
  747. begin
  748. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  749. FromSize := ToSize;
  750. case ToSize of
  751. { signed integer registers }
  752. OS_8,
  753. OS_S8:
  754. oppostfix:=PF_B;
  755. OS_16,
  756. OS_S16:
  757. oppostfix:=PF_H;
  758. OS_32,
  759. OS_S32:
  760. oppostfix:=PF_None;
  761. else
  762. InternalError(200308295);
  763. end;
  764. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
  765. begin
  766. if target_info.endian=endian_big then
  767. dir:=-1
  768. else
  769. dir:=1;
  770. case FromSize of
  771. OS_16,OS_S16:
  772. begin
  773. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  774. tmpreg:=getintregister(list,OS_INT);
  775. usedtmpref:=ref;
  776. if target_info.endian=endian_big then
  777. inc(usedtmpref.offset,1);
  778. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  779. inc(usedtmpref.offset,dir);
  780. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  781. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  782. end;
  783. OS_32,OS_S32:
  784. begin
  785. tmpreg:=getintregister(list,OS_INT);
  786. usedtmpref:=ref;
  787. shifterop_reset(so);so.shiftmode:=SM_LSR;
  788. if ref.alignment=2 then
  789. begin
  790. so.shiftimm:=16;
  791. if target_info.endian=endian_big then
  792. inc(usedtmpref.offset,2);
  793. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  794. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  795. inc(usedtmpref.offset,dir*2);
  796. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  797. end
  798. else
  799. begin
  800. so.shiftimm:=8;
  801. if target_info.endian=endian_big then
  802. inc(usedtmpref.offset,3);
  803. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  804. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  805. inc(usedtmpref.offset,dir);
  806. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  807. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  808. inc(usedtmpref.offset,dir);
  809. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  810. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  811. inc(usedtmpref.offset,dir);
  812. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  813. end;
  814. end
  815. else
  816. handle_load_store(list,A_STR,oppostfix,reg,ref);
  817. end;
  818. end
  819. else
  820. handle_load_store(list,A_STR,oppostfix,reg,ref);
  821. end;
  822. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  823. var
  824. oppostfix:toppostfix;
  825. usedtmpref: treference;
  826. tmpreg,tmpreg2 : tregister;
  827. so : tshifterop;
  828. dir : integer;
  829. begin
  830. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  831. FromSize := ToSize;
  832. case FromSize of
  833. { signed integer registers }
  834. OS_8:
  835. oppostfix:=PF_B;
  836. OS_S8:
  837. oppostfix:=PF_SB;
  838. OS_16:
  839. oppostfix:=PF_H;
  840. OS_S16:
  841. oppostfix:=PF_SH;
  842. OS_32,
  843. OS_S32:
  844. oppostfix:=PF_None;
  845. else
  846. InternalError(200308297);
  847. end;
  848. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  849. begin
  850. if target_info.endian=endian_big then
  851. dir:=-1
  852. else
  853. dir:=1;
  854. case FromSize of
  855. OS_16,OS_S16:
  856. begin
  857. { only complicated references need an extra loadaddr }
  858. if assigned(ref.symbol) or
  859. (ref.index<>NR_NO) or
  860. (ref.offset<-4095) or
  861. (ref.offset>4094) or
  862. { sometimes the compiler reused registers }
  863. (reg=ref.index) or
  864. (reg=ref.base) then
  865. begin
  866. tmpreg2:=getintregister(list,OS_INT);
  867. a_loadaddr_ref_reg(list,ref,tmpreg2);
  868. reference_reset_base(usedtmpref,tmpreg2,0);
  869. end
  870. else
  871. usedtmpref:=ref;
  872. if target_info.endian=endian_big then
  873. inc(usedtmpref.offset,1);
  874. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  875. tmpreg:=getintregister(list,OS_INT);
  876. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  877. inc(usedtmpref.offset,dir);
  878. if FromSize=OS_16 then
  879. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  880. else
  881. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  882. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  883. end;
  884. OS_32,OS_S32:
  885. begin
  886. tmpreg:=getintregister(list,OS_INT);
  887. { only complicated references need an extra loadaddr }
  888. if assigned(ref.symbol) or
  889. (ref.index<>NR_NO) or
  890. (ref.offset<-4095) or
  891. (ref.offset>4092) or
  892. { sometimes the compiler reused registers }
  893. (reg=ref.index) or
  894. (reg=ref.base) then
  895. begin
  896. tmpreg2:=getintregister(list,OS_INT);
  897. a_loadaddr_ref_reg(list,ref,tmpreg2);
  898. reference_reset_base(usedtmpref,tmpreg2,0);
  899. end
  900. else
  901. usedtmpref:=ref;
  902. shifterop_reset(so);so.shiftmode:=SM_LSL;
  903. if ref.alignment=2 then
  904. begin
  905. if target_info.endian=endian_big then
  906. inc(usedtmpref.offset,2);
  907. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  908. inc(usedtmpref.offset,dir*2);
  909. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  910. so.shiftimm:=16;
  911. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  912. end
  913. else
  914. begin
  915. if target_info.endian=endian_big then
  916. inc(usedtmpref.offset,3);
  917. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  918. inc(usedtmpref.offset,dir);
  919. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  920. so.shiftimm:=8;
  921. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  922. inc(usedtmpref.offset,dir);
  923. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  924. so.shiftimm:=16;
  925. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  926. inc(usedtmpref.offset,dir);
  927. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  928. so.shiftimm:=24;
  929. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  930. end;
  931. end
  932. else
  933. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  934. end;
  935. end
  936. else
  937. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  938. if (fromsize=OS_S8) and (tosize = OS_16) then
  939. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  940. end;
  941. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  942. var
  943. oppostfix:toppostfix;
  944. begin
  945. case ToSize of
  946. { signed integer registers }
  947. OS_8,
  948. OS_S8:
  949. oppostfix:=PF_B;
  950. OS_16,
  951. OS_S16:
  952. oppostfix:=PF_H;
  953. OS_32,
  954. OS_S32:
  955. oppostfix:=PF_None;
  956. else
  957. InternalError(2003082910);
  958. end;
  959. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  960. end;
  961. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  962. var
  963. oppostfix:toppostfix;
  964. begin
  965. case FromSize of
  966. { signed integer registers }
  967. OS_8:
  968. oppostfix:=PF_B;
  969. OS_S8:
  970. oppostfix:=PF_SB;
  971. OS_16:
  972. oppostfix:=PF_H;
  973. OS_S16:
  974. oppostfix:=PF_SH;
  975. OS_32,
  976. OS_S32:
  977. oppostfix:=PF_None;
  978. else
  979. InternalError(200308291);
  980. end;
  981. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  982. end;
  983. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  984. var
  985. so : tshifterop;
  986. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  987. begin
  988. so.shiftmode:=shiftmode;
  989. so.shiftimm:=shiftimm;
  990. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  991. end;
  992. var
  993. instr: taicpu;
  994. conv_done: boolean;
  995. begin
  996. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  997. internalerror(2002090901);
  998. conv_done:=false;
  999. if tosize<>fromsize then
  1000. begin
  1001. shifterop_reset(so);
  1002. conv_done:=true;
  1003. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1004. fromsize:=tosize;
  1005. case fromsize of
  1006. OS_8:
  1007. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1008. OS_S8:
  1009. begin
  1010. do_shift(SM_LSL,24,reg1);
  1011. if tosize=OS_16 then
  1012. begin
  1013. do_shift(SM_ASR,8,reg2);
  1014. do_shift(SM_LSR,16,reg2);
  1015. end
  1016. else
  1017. do_shift(SM_ASR,24,reg2);
  1018. end;
  1019. OS_16:
  1020. begin
  1021. do_shift(SM_LSL,16,reg1);
  1022. do_shift(SM_LSR,16,reg2);
  1023. end;
  1024. OS_S16:
  1025. begin
  1026. do_shift(SM_LSL,16,reg1);
  1027. do_shift(SM_ASR,16,reg2)
  1028. end;
  1029. else
  1030. conv_done:=false;
  1031. end;
  1032. end;
  1033. if not conv_done and (reg1<>reg2) then
  1034. begin
  1035. { same size, only a register mov required }
  1036. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1037. list.Concat(instr);
  1038. { Notify the register allocator that we have written a move instruction so
  1039. it can try to eliminate it. }
  1040. add_move_instruction(instr);
  1041. end;
  1042. end;
  1043. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  1044. var
  1045. href,href2 : treference;
  1046. hloc : pcgparalocation;
  1047. begin
  1048. href:=ref;
  1049. hloc:=paraloc.location;
  1050. while assigned(hloc) do
  1051. begin
  1052. case hloc^.loc of
  1053. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1054. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1055. LOC_REGISTER :
  1056. case hloc^.size of
  1057. OS_F32:
  1058. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1059. OS_64,
  1060. OS_F64:
  1061. cg64.a_param64_ref(list,href,paraloc);
  1062. else
  1063. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1064. end;
  1065. LOC_REFERENCE :
  1066. begin
  1067. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  1068. { concatcopy should choose the best way to copy the data }
  1069. g_concatcopy(list,href,href2,tcgsize2size[size]);
  1070. end;
  1071. else
  1072. internalerror(200408241);
  1073. end;
  1074. inc(href.offset,tcgsize2size[hloc^.size]);
  1075. hloc:=hloc^.next;
  1076. end;
  1077. end;
  1078. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1079. begin
  1080. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1081. end;
  1082. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1083. var
  1084. oppostfix:toppostfix;
  1085. begin
  1086. case fromsize of
  1087. OS_32,
  1088. OS_F32:
  1089. oppostfix:=PF_S;
  1090. OS_64,
  1091. OS_F64:
  1092. oppostfix:=PF_D;
  1093. OS_F80:
  1094. oppostfix:=PF_E;
  1095. else
  1096. InternalError(200309021);
  1097. end;
  1098. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1099. if fromsize<>tosize then
  1100. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1101. end;
  1102. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1103. var
  1104. oppostfix:toppostfix;
  1105. begin
  1106. case tosize of
  1107. OS_F32:
  1108. oppostfix:=PF_S;
  1109. OS_F64:
  1110. oppostfix:=PF_D;
  1111. OS_F80:
  1112. oppostfix:=PF_E;
  1113. else
  1114. InternalError(200309022);
  1115. end;
  1116. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1117. end;
  1118. { comparison operations }
  1119. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  1120. l : tasmlabel);
  1121. var
  1122. tmpreg : tregister;
  1123. b : byte;
  1124. begin
  1125. if is_shifter_const(a,b) then
  1126. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1127. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1128. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1129. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1130. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1131. else
  1132. begin
  1133. tmpreg:=getintregister(list,size);
  1134. a_load_const_reg(list,size,a,tmpreg);
  1135. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1136. end;
  1137. a_jmp_cond(list,cmp_op,l);
  1138. end;
  1139. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1140. begin
  1141. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1142. a_jmp_cond(list,cmp_op,l);
  1143. end;
  1144. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1145. var
  1146. ai : taicpu;
  1147. begin
  1148. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1149. ai.is_jmp:=true;
  1150. list.concat(ai);
  1151. end;
  1152. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1153. var
  1154. ai : taicpu;
  1155. begin
  1156. ai:=taicpu.op_sym(A_B,l);
  1157. ai.is_jmp:=true;
  1158. list.concat(ai);
  1159. end;
  1160. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1161. var
  1162. ai : taicpu;
  1163. begin
  1164. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1165. ai.is_jmp:=true;
  1166. list.concat(ai);
  1167. end;
  1168. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1169. begin
  1170. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1171. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1172. end;
  1173. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1174. var
  1175. ref : treference;
  1176. shift : byte;
  1177. firstfloatreg,lastfloatreg,
  1178. r : byte;
  1179. regs : tcpuregisterset;
  1180. begin
  1181. LocalSize:=align(LocalSize,4);
  1182. if not(nostackframe) then
  1183. begin
  1184. firstfloatreg:=RS_NO;
  1185. { save floating point registers? }
  1186. for r:=RS_F0 to RS_F7 do
  1187. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1188. begin
  1189. if firstfloatreg=RS_NO then
  1190. firstfloatreg:=r;
  1191. lastfloatreg:=r;
  1192. end;
  1193. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1194. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1195. begin
  1196. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1197. a_reg_alloc(list,NR_R12);
  1198. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1199. end;
  1200. { save int registers }
  1201. reference_reset(ref);
  1202. ref.index:=NR_STACK_POINTER_REG;
  1203. ref.addressmode:=AM_PREINDEXED;
  1204. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1205. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1206. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1207. else
  1208. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1209. include(regs,RS_R14);
  1210. if regs<>[] then
  1211. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1212. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1213. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1214. (* allocate necessary stack size
  1215. not necessary according to Yury Sidorov
  1216. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1217. in the entry/exit code }
  1218. if (target_info.system in [system_arm_wince]) and
  1219. (localsize>=winstackpagesize) then
  1220. begin
  1221. if localsize div winstackpagesize<=5 then
  1222. begin
  1223. if is_shifter_const(localsize,shift) then
  1224. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
  1225. else
  1226. begin
  1227. a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
  1228. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1229. end;
  1230. for i:=1 to localsize div winstackpagesize do
  1231. begin
  1232. if localsize-i*winstackpagesize<4096 then
  1233. reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
  1234. else
  1235. begin
  1236. a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
  1237. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1238. href.index:=NR_R12;
  1239. end;
  1240. { the data stored doesn't matter }
  1241. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1242. end;
  1243. a_reg_dealloc(list,NR_R12);
  1244. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1245. { the data stored doesn't matter }
  1246. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1247. end
  1248. else
  1249. begin
  1250. current_asmdata.getjumplabel(again);
  1251. list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
  1252. a_label(list,again);
  1253. { always shifterop }
  1254. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
  1255. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1256. { the data stored doesn't matter }
  1257. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1258. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
  1259. a_jmp_cond(list,OC_NE,again);
  1260. if is_shifter_const(localsize mod winstackpagesize,shift) then
  1261. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
  1262. else
  1263. begin
  1264. a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
  1265. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1266. end;
  1267. a_reg_dealloc(list,NR_R12);
  1268. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1269. { the data stored doesn't matter }
  1270. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1271. end
  1272. end
  1273. else
  1274. *)
  1275. if LocalSize<>0 then
  1276. if not(is_shifter_const(localsize,shift)) then
  1277. begin
  1278. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1279. a_reg_alloc(list,NR_R12);
  1280. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1281. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1282. a_reg_dealloc(list,NR_R12);
  1283. end
  1284. else
  1285. begin
  1286. a_reg_dealloc(list,NR_R12);
  1287. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1288. end;
  1289. if firstfloatreg<>RS_NO then
  1290. begin
  1291. reference_reset(ref);
  1292. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1293. begin
  1294. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1295. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1296. ref.base:=NR_R12;
  1297. end
  1298. else
  1299. begin
  1300. ref.base:=current_procinfo.framepointer;
  1301. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1302. end;
  1303. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1304. lastfloatreg-firstfloatreg+1,ref));
  1305. end;
  1306. end;
  1307. end;
  1308. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1309. var
  1310. ref : treference;
  1311. firstfloatreg,lastfloatreg,
  1312. r : byte;
  1313. shift : byte;
  1314. regs : tcpuregisterset;
  1315. LocalSize : longint;
  1316. begin
  1317. if not(nostackframe) then
  1318. begin
  1319. { restore floating point register }
  1320. firstfloatreg:=RS_NO;
  1321. { save floating point registers? }
  1322. for r:=RS_F0 to RS_F7 do
  1323. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1324. begin
  1325. if firstfloatreg=RS_NO then
  1326. firstfloatreg:=r;
  1327. lastfloatreg:=r;
  1328. end;
  1329. if firstfloatreg<>RS_NO then
  1330. begin
  1331. reference_reset(ref);
  1332. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1333. begin
  1334. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1335. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1336. ref.base:=NR_R12;
  1337. end
  1338. else
  1339. begin
  1340. ref.base:=current_procinfo.framepointer;
  1341. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1342. end;
  1343. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1344. lastfloatreg-firstfloatreg+1,ref));
  1345. end;
  1346. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1347. begin
  1348. LocalSize:=current_procinfo.calc_stackframe_size;
  1349. if LocalSize<>0 then
  1350. if not(is_shifter_const(LocalSize,shift)) then
  1351. begin
  1352. a_reg_alloc(list,NR_R12);
  1353. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1354. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1355. a_reg_dealloc(list,NR_R12);
  1356. end
  1357. else
  1358. begin
  1359. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1360. end;
  1361. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1362. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1363. begin
  1364. exclude(regs,RS_R14);
  1365. include(regs,RS_R15);
  1366. end;
  1367. if regs=[] then
  1368. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1369. else
  1370. begin
  1371. reference_reset(ref);
  1372. ref.index:=NR_STACK_POINTER_REG;
  1373. ref.addressmode:=AM_PREINDEXED;
  1374. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1375. end;
  1376. end
  1377. else
  1378. begin
  1379. { restore int registers and return }
  1380. reference_reset(ref);
  1381. ref.index:=NR_FRAME_POINTER_REG;
  1382. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
  1383. end;
  1384. end
  1385. else
  1386. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1387. end;
  1388. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1389. var
  1390. b : byte;
  1391. tmpref : treference;
  1392. instr : taicpu;
  1393. begin
  1394. if ref.addressmode<>AM_OFFSET then
  1395. internalerror(200309071);
  1396. tmpref:=ref;
  1397. { Be sure to have a base register }
  1398. if (tmpref.base=NR_NO) then
  1399. begin
  1400. if tmpref.shiftmode<>SM_None then
  1401. internalerror(200308294);
  1402. if tmpref.signindex<0 then
  1403. internalerror(200312023);
  1404. tmpref.base:=tmpref.index;
  1405. tmpref.index:=NR_NO;
  1406. end;
  1407. if assigned(tmpref.symbol) or
  1408. not((is_shifter_const(tmpref.offset,b)) or
  1409. (is_shifter_const(-tmpref.offset,b))
  1410. ) then
  1411. fixref(list,tmpref);
  1412. { expect a base here if there is an index }
  1413. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1414. internalerror(200312022);
  1415. if tmpref.index<>NR_NO then
  1416. begin
  1417. if tmpref.shiftmode<>SM_None then
  1418. internalerror(200312021);
  1419. if tmpref.signindex<0 then
  1420. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1421. else
  1422. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1423. if tmpref.offset<>0 then
  1424. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1425. end
  1426. else
  1427. begin
  1428. if tmpref.base=NR_NO then
  1429. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1430. else
  1431. if tmpref.offset<>0 then
  1432. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1433. else
  1434. begin
  1435. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1436. list.concat(instr);
  1437. add_move_instruction(instr);
  1438. end;
  1439. end;
  1440. end;
  1441. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1442. var
  1443. tmpreg : tregister;
  1444. tmpref : treference;
  1445. l : tasmlabel;
  1446. begin
  1447. { absolute symbols can't be handled directly, we've to store the symbol reference
  1448. in the text segment and access it pc relative
  1449. For now, we assume that references where base or index equals to PC are already
  1450. relative, all other references are assumed to be absolute and thus they need
  1451. to be handled extra.
  1452. A proper solution would be to change refoptions to a set and store the information
  1453. if the symbol is absolute or relative there.
  1454. }
  1455. { create consts entry }
  1456. reference_reset(tmpref);
  1457. current_asmdata.getjumplabel(l);
  1458. cg.a_label(current_procinfo.aktlocaldata,l);
  1459. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1460. if assigned(ref.symbol) then
  1461. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1462. else
  1463. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1464. { load consts entry }
  1465. tmpreg:=getintregister(list,OS_INT);
  1466. tmpref.symbol:=l;
  1467. tmpref.base:=NR_PC;
  1468. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1469. if (ref.base<>NR_NO) then
  1470. begin
  1471. if ref.index<>NR_NO then
  1472. begin
  1473. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1474. ref.base:=tmpreg;
  1475. end
  1476. else
  1477. if ref.base<>NR_PC then
  1478. begin
  1479. ref.index:=tmpreg;
  1480. ref.shiftimm:=0;
  1481. ref.signindex:=1;
  1482. ref.shiftmode:=SM_None;
  1483. end
  1484. else
  1485. ref.base:=tmpreg;
  1486. end
  1487. else
  1488. ref.base:=tmpreg;
  1489. ref.offset:=0;
  1490. ref.symbol:=nil;
  1491. end;
  1492. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1493. var
  1494. paraloc1,paraloc2,paraloc3 : TCGPara;
  1495. begin
  1496. paraloc1.init;
  1497. paraloc2.init;
  1498. paraloc3.init;
  1499. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1500. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1501. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1502. paramanager.allocparaloc(list,paraloc3);
  1503. a_param_const(list,OS_INT,len,paraloc3);
  1504. paramanager.allocparaloc(list,paraloc2);
  1505. a_paramaddr_ref(list,dest,paraloc2);
  1506. paramanager.allocparaloc(list,paraloc2);
  1507. a_paramaddr_ref(list,source,paraloc1);
  1508. paramanager.freeparaloc(list,paraloc3);
  1509. paramanager.freeparaloc(list,paraloc2);
  1510. paramanager.freeparaloc(list,paraloc1);
  1511. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1512. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1513. a_call_name(list,'FPC_MOVE');
  1514. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1515. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1516. paraloc3.done;
  1517. paraloc2.done;
  1518. paraloc1.done;
  1519. end;
  1520. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1521. const
  1522. maxtmpreg=10;{roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
  1523. var
  1524. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1525. srcreg,destreg,countreg,r,tmpreg:tregister;
  1526. helpsize:aint;
  1527. copysize:byte;
  1528. cgsize:Tcgsize;
  1529. tmpregisters:array[1..maxtmpreg] of tregister;
  1530. tmpregi,tmpregi2:byte;
  1531. { will never be called with count<=4 }
  1532. procedure genloop(count : aword;size : byte);
  1533. const
  1534. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1535. var
  1536. l : tasmlabel;
  1537. begin
  1538. current_asmdata.getjumplabel(l);
  1539. if count<size then size:=1;
  1540. a_load_const_reg(list,OS_INT,count div size,countreg);
  1541. cg.a_label(list,l);
  1542. srcref.addressmode:=AM_POSTINDEXED;
  1543. dstref.addressmode:=AM_POSTINDEXED;
  1544. srcref.offset:=size;
  1545. dstref.offset:=size;
  1546. r:=getintregister(list,size2opsize[size]);
  1547. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1548. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1549. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1550. a_jmp_flags(list,F_NE,l);
  1551. srcref.offset:=1;
  1552. dstref.offset:=1;
  1553. case count mod size of
  1554. 1:
  1555. begin
  1556. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1557. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1558. end;
  1559. 2:
  1560. if aligned then
  1561. begin
  1562. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1563. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1564. end
  1565. else
  1566. begin
  1567. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1568. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1569. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1570. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1571. end;
  1572. 3:
  1573. if aligned then
  1574. begin
  1575. srcref.offset:=2;
  1576. dstref.offset:=2;
  1577. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1578. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1579. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1580. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1581. end
  1582. else
  1583. begin
  1584. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1585. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1586. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1587. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1588. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1589. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1590. end;
  1591. end;
  1592. { keep the registers alive }
  1593. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1594. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1595. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1596. end;
  1597. begin
  1598. if len=0 then
  1599. exit;
  1600. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1601. dstref:=dest;
  1602. srcref:=source;
  1603. if cs_opt_size in current_settings.optimizerswitches then
  1604. helpsize:=8;
  1605. if (len<=helpsize) and aligned then
  1606. begin
  1607. tmpregi:=0;
  1608. srcreg:=getintregister(list,OS_ADDR);
  1609. { explicit pc relative addressing, could be
  1610. e.g. a floating point constant }
  1611. if source.base=NR_PC then
  1612. begin
  1613. { ... then we don't need a loadaddr }
  1614. srcref:=source;
  1615. end
  1616. else
  1617. begin
  1618. a_loadaddr_ref_reg(list,source,srcreg);
  1619. reference_reset_base(srcref,srcreg,0);
  1620. end;
  1621. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1622. begin
  1623. inc(tmpregi);
  1624. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1625. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1626. inc(srcref.offset,4);
  1627. dec(len,4);
  1628. end;
  1629. destreg:=getintregister(list,OS_ADDR);
  1630. a_loadaddr_ref_reg(list,dest,destreg);
  1631. reference_reset_base(dstref,destreg,0);
  1632. tmpregi2:=1;
  1633. while (tmpregi2<=tmpregi) do
  1634. begin
  1635. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1636. inc(dstref.offset,4);
  1637. inc(tmpregi2);
  1638. end;
  1639. copysize:=4;
  1640. cgsize:=OS_32;
  1641. while len<>0 do
  1642. begin
  1643. if len<2 then
  1644. begin
  1645. copysize:=1;
  1646. cgsize:=OS_8;
  1647. end
  1648. else if len<4 then
  1649. begin
  1650. copysize:=2;
  1651. cgsize:=OS_16;
  1652. end;
  1653. dec(len,copysize);
  1654. r:=getintregister(list,cgsize);
  1655. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1656. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1657. inc(srcref.offset,copysize);
  1658. inc(dstref.offset,copysize);
  1659. end;{end of while}
  1660. end
  1661. else
  1662. begin
  1663. cgsize:=OS_32;
  1664. if (len<=4) then{len<=4 and not aligned}
  1665. begin
  1666. r:=getintregister(list,cgsize);
  1667. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1668. if Len=1 then
  1669. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1670. else
  1671. begin
  1672. tmpreg:=getintregister(list,cgsize);
  1673. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1674. inc(usedtmpref.offset,1);
  1675. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1676. inc(usedtmpref2.offset,1);
  1677. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1678. if len>2 then
  1679. begin
  1680. inc(usedtmpref.offset,1);
  1681. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1682. inc(usedtmpref2.offset,1);
  1683. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1684. if len>3 then
  1685. begin
  1686. inc(usedtmpref.offset,1);
  1687. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1688. inc(usedtmpref2.offset,1);
  1689. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1690. end;
  1691. end;
  1692. end;
  1693. end{end of if len<=4}
  1694. else
  1695. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1696. destreg:=getintregister(list,OS_ADDR);
  1697. a_loadaddr_ref_reg(list,dest,destreg);
  1698. reference_reset_base(dstref,destreg,0);
  1699. srcreg:=getintregister(list,OS_ADDR);
  1700. a_loadaddr_ref_reg(list,source,srcreg);
  1701. reference_reset_base(srcref,srcreg,0);
  1702. countreg:=getintregister(list,OS_32);
  1703. // if cs_opt_size in current_settings.optimizerswitches then
  1704. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1705. {if aligned then
  1706. genloop(len,4)
  1707. else}
  1708. genloop(len,1);
  1709. end;
  1710. end;
  1711. end;
  1712. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1713. begin
  1714. g_concatcopy_internal(list,source,dest,len,false);
  1715. end;
  1716. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1717. begin
  1718. if (source.alignment in [1..3]) or
  1719. (dest.alignment in [1..3]) then
  1720. g_concatcopy_internal(list,source,dest,len,false)
  1721. else
  1722. g_concatcopy_internal(list,source,dest,len,true);
  1723. end;
  1724. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1725. var
  1726. ovloc : tlocation;
  1727. begin
  1728. ovloc.loc:=LOC_VOID;
  1729. g_overflowCheck_loc(list,l,def,ovloc);
  1730. end;
  1731. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1732. var
  1733. hl : tasmlabel;
  1734. ai:TAiCpu;
  1735. hflags : tresflags;
  1736. begin
  1737. if not(cs_check_overflow in current_settings.localswitches) then
  1738. exit;
  1739. current_asmdata.getjumplabel(hl);
  1740. case ovloc.loc of
  1741. LOC_VOID:
  1742. begin
  1743. ai:=taicpu.op_sym(A_B,hl);
  1744. ai.is_jmp:=true;
  1745. if not((def.typ=pointerdef) or
  1746. ((def.typ=orddef) and
  1747. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,pasbool]))) then
  1748. ai.SetCondition(C_VC)
  1749. else
  1750. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1751. ai.SetCondition(C_CS)
  1752. else
  1753. ai.SetCondition(C_CC);
  1754. list.concat(ai);
  1755. end;
  1756. LOC_FLAGS:
  1757. begin
  1758. hflags:=ovloc.resflags;
  1759. inverse_flags(hflags);
  1760. cg.a_jmp_flags(list,hflags,hl);
  1761. end;
  1762. else
  1763. internalerror(200409281);
  1764. end;
  1765. a_call_name(list,'FPC_OVERFLOW');
  1766. a_label(list,hl);
  1767. end;
  1768. procedure tcgarm.g_save_registers(list : TAsmList);
  1769. begin
  1770. { this work is done in g_proc_entry }
  1771. end;
  1772. procedure tcgarm.g_restore_registers(list : TAsmList);
  1773. begin
  1774. { this work is done in g_proc_exit }
  1775. end;
  1776. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1777. var
  1778. ai : taicpu;
  1779. begin
  1780. ai:=Taicpu.Op_sym(A_B,l);
  1781. ai.SetCondition(OpCmp2AsmCond[cond]);
  1782. ai.is_jmp:=true;
  1783. list.concat(ai);
  1784. end;
  1785. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);
  1786. var
  1787. hsym : tsym;
  1788. href : treference;
  1789. paraloc : Pcgparalocation;
  1790. shift : byte;
  1791. begin
  1792. { calculate the parameter info for the procdef }
  1793. if not procdef.has_paraloc_info then
  1794. begin
  1795. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  1796. procdef.has_paraloc_info:=true;
  1797. end;
  1798. hsym:=tsym(procdef.parast.Find('self'));
  1799. if not(assigned(hsym) and
  1800. (hsym.typ=paravarsym)) then
  1801. internalerror(200305251);
  1802. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1803. while paraloc<>nil do
  1804. with paraloc^ do
  1805. begin
  1806. case loc of
  1807. LOC_REGISTER:
  1808. begin
  1809. if is_shifter_const(ioffset,shift) then
  1810. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  1811. else
  1812. begin
  1813. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1814. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  1815. end;
  1816. end;
  1817. LOC_REFERENCE:
  1818. begin
  1819. { offset in the wrapper needs to be adjusted for the stored
  1820. return address }
  1821. reference_reset_base(href,reference.index,reference.offset+sizeof(aint));
  1822. if is_shifter_const(ioffset,shift) then
  1823. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  1824. else
  1825. begin
  1826. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1827. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  1828. end;
  1829. end
  1830. else
  1831. internalerror(200309189);
  1832. end;
  1833. paraloc:=next;
  1834. end;
  1835. end;
  1836. procedure tcgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1837. begin
  1838. internalerror(200807237);
  1839. end;
  1840. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1841. procedure loadvmttor12;
  1842. var
  1843. href : treference;
  1844. begin
  1845. reference_reset_base(href,NR_R0,0);
  1846. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1847. end;
  1848. procedure op_onr12methodaddr;
  1849. var
  1850. href : treference;
  1851. begin
  1852. if (procdef.extnumber=$ffff) then
  1853. Internalerror(200006139);
  1854. { call/jmp vmtoffs(%eax) ; method offs }
  1855. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1856. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1857. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1858. end;
  1859. var
  1860. make_global : boolean;
  1861. begin
  1862. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1863. Internalerror(200006137);
  1864. if not assigned(procdef._class) or
  1865. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1866. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1867. Internalerror(200006138);
  1868. if procdef.owner.symtabletype<>ObjectSymtable then
  1869. Internalerror(200109191);
  1870. make_global:=false;
  1871. if (not current_module.is_unit) or
  1872. create_smartlink or
  1873. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1874. make_global:=true;
  1875. if make_global then
  1876. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1877. else
  1878. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1879. { the wrapper might need aktlocaldata for the additional data to
  1880. load the constant }
  1881. current_procinfo:=cprocinfo.create(nil);
  1882. { set param1 interface to self }
  1883. g_adjust_self_value(list,procdef,ioffset);
  1884. { case 4 }
  1885. if po_virtualmethod in procdef.procoptions then
  1886. begin
  1887. loadvmttor12;
  1888. op_onr12methodaddr;
  1889. end
  1890. { case 0 }
  1891. else
  1892. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1893. list.concatlist(current_procinfo.aktlocaldata);
  1894. current_procinfo.Free;
  1895. current_procinfo:=nil;
  1896. list.concat(Tai_symbol_end.Createname(labelname));
  1897. end;
  1898. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  1899. const
  1900. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1901. begin
  1902. if (op in overflowops) and
  1903. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1904. a_load_reg_reg(list,OS_32,size,dst,dst);
  1905. end;
  1906. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1907. begin
  1908. case op of
  1909. OP_NEG:
  1910. begin
  1911. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1912. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1913. end;
  1914. OP_NOT:
  1915. begin
  1916. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1917. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1918. end;
  1919. else
  1920. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1921. end;
  1922. end;
  1923. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1924. begin
  1925. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1926. end;
  1927. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1928. var
  1929. ovloc : tlocation;
  1930. begin
  1931. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1932. end;
  1933. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1934. var
  1935. ovloc : tlocation;
  1936. begin
  1937. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1938. end;
  1939. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1940. var
  1941. tmpreg : tregister;
  1942. b : byte;
  1943. begin
  1944. ovloc.loc:=LOC_VOID;
  1945. case op of
  1946. OP_NEG,
  1947. OP_NOT :
  1948. internalerror(200306017);
  1949. end;
  1950. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1951. begin
  1952. case op of
  1953. OP_ADD:
  1954. begin
  1955. if is_shifter_const(lo(value),b) then
  1956. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1957. else
  1958. begin
  1959. tmpreg:=cg.getintregister(list,OS_32);
  1960. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1961. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1962. end;
  1963. if is_shifter_const(hi(value),b) then
  1964. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1965. else
  1966. begin
  1967. tmpreg:=cg.getintregister(list,OS_32);
  1968. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1969. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1970. end;
  1971. end;
  1972. OP_SUB:
  1973. begin
  1974. if is_shifter_const(lo(value),b) then
  1975. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1976. else
  1977. begin
  1978. tmpreg:=cg.getintregister(list,OS_32);
  1979. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1980. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1981. end;
  1982. if is_shifter_const(hi(value),b) then
  1983. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  1984. else
  1985. begin
  1986. tmpreg:=cg.getintregister(list,OS_32);
  1987. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1988. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1989. end;
  1990. end;
  1991. else
  1992. internalerror(200502131);
  1993. end;
  1994. if size=OS_64 then
  1995. begin
  1996. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1997. ovloc.loc:=LOC_FLAGS;
  1998. case op of
  1999. OP_ADD:
  2000. ovloc.resflags:=F_CS;
  2001. OP_SUB:
  2002. ovloc.resflags:=F_CC;
  2003. end;
  2004. end;
  2005. end
  2006. else
  2007. begin
  2008. case op of
  2009. OP_AND,OP_OR,OP_XOR:
  2010. begin
  2011. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2012. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2013. end;
  2014. OP_ADD:
  2015. begin
  2016. if is_shifter_const(aint(lo(value)),b) then
  2017. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2018. else
  2019. begin
  2020. tmpreg:=cg.getintregister(list,OS_32);
  2021. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2022. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2023. end;
  2024. if is_shifter_const(aint(hi(value)),b) then
  2025. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2026. else
  2027. begin
  2028. tmpreg:=cg.getintregister(list,OS_32);
  2029. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2030. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2031. end;
  2032. end;
  2033. OP_SUB:
  2034. begin
  2035. if is_shifter_const(aint(lo(value)),b) then
  2036. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2037. else
  2038. begin
  2039. tmpreg:=cg.getintregister(list,OS_32);
  2040. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2041. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2042. end;
  2043. if is_shifter_const(aint(hi(value)),b) then
  2044. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2045. else
  2046. begin
  2047. tmpreg:=cg.getintregister(list,OS_32);
  2048. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2049. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2050. end;
  2051. end;
  2052. else
  2053. internalerror(2003083101);
  2054. end;
  2055. end;
  2056. end;
  2057. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2058. begin
  2059. ovloc.loc:=LOC_VOID;
  2060. case op of
  2061. OP_NEG,
  2062. OP_NOT :
  2063. internalerror(200306017);
  2064. end;
  2065. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2066. begin
  2067. case op of
  2068. OP_ADD:
  2069. begin
  2070. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2071. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2072. end;
  2073. OP_SUB:
  2074. begin
  2075. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2076. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2077. end;
  2078. else
  2079. internalerror(2003083101);
  2080. end;
  2081. if size=OS_64 then
  2082. begin
  2083. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2084. ovloc.loc:=LOC_FLAGS;
  2085. case op of
  2086. OP_ADD:
  2087. ovloc.resflags:=F_CS;
  2088. OP_SUB:
  2089. ovloc.resflags:=F_CC;
  2090. end;
  2091. end;
  2092. end
  2093. else
  2094. begin
  2095. case op of
  2096. OP_AND,OP_OR,OP_XOR:
  2097. begin
  2098. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2099. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2100. end;
  2101. OP_ADD:
  2102. begin
  2103. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2104. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2105. end;
  2106. OP_SUB:
  2107. begin
  2108. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2109. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2110. end;
  2111. else
  2112. internalerror(2003083101);
  2113. end;
  2114. end;
  2115. end;
  2116. begin
  2117. cg:=tcgarm.create;
  2118. cg64:=tcg64farm.create;
  2119. end.