cgcpu.pas 84 KB

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