cgcpu.pas 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  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,
  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 : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : taasmoutput;const s : string);override;
  37. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  38. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  39. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  40. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  41. size: tcgsize; a: aint; src, dst: tregister); override;
  42. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  43. size: tcgsize; src1, src2, dst: tregister); override;
  44. procedure a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  45. procedure a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. { move instructions }
  47. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);override;
  48. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  49. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  50. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  51. { fpu move instructions }
  52. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  53. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  54. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  55. procedure a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  56. { comparison operations }
  57. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  58. l : tasmlabel);override;
  59. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  60. procedure a_jmp_name(list : taasmoutput;const s : string); override;
  61. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  62. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  63. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  64. procedure g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);override;
  65. procedure g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean); override;
  66. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  67. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);override;
  68. procedure g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);override;
  69. procedure g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  70. procedure g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  71. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  72. procedure g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  73. procedure g_save_standard_registers(list : taasmoutput);override;
  74. procedure g_restore_standard_registers(list : taasmoutput);override;
  75. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  76. procedure fixref(list : taasmoutput;var ref : treference);
  77. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  78. procedure g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  79. end;
  80. tcg64farm = class(tcg64f32)
  81. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  82. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  83. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  84. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  85. procedure a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  86. procedure a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  87. end;
  88. const
  89. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  90. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  91. function get_fpu_postfix(def : tdef) : toppostfix;
  92. implementation
  93. uses
  94. globals,verbose,systems,cutils,
  95. fmodule,
  96. symconst,symsym,
  97. tgobj,
  98. procinfo,cpupi,
  99. paramgr;
  100. function get_fpu_postfix(def : tdef) : toppostfix;
  101. begin
  102. if def.deftype=floatdef then
  103. begin
  104. case tfloatdef(def).typ of
  105. s32real:
  106. result:=PF_S;
  107. s64real:
  108. result:=PF_D;
  109. s80real:
  110. result:=PF_E;
  111. else
  112. internalerror(200401272);
  113. end;
  114. end
  115. else
  116. internalerror(200401271);
  117. end;
  118. procedure tcgarm.init_register_allocators;
  119. begin
  120. inherited init_register_allocators;
  121. { currently, we save R14 always, so we can use it }
  122. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  123. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  124. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  125. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  126. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  127. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  128. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  129. end;
  130. procedure tcgarm.done_register_allocators;
  131. begin
  132. rg[R_INTREGISTER].free;
  133. rg[R_FPUREGISTER].free;
  134. rg[R_MMREGISTER].free;
  135. inherited done_register_allocators;
  136. end;
  137. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);
  138. var
  139. ref: treference;
  140. begin
  141. paraloc.check_simple_location;
  142. case paraloc.location^.loc of
  143. LOC_REGISTER,LOC_CREGISTER:
  144. a_load_const_reg(list,size,a,paraloc.location^.register);
  145. LOC_REFERENCE:
  146. begin
  147. reference_reset(ref);
  148. ref.base:=paraloc.location^.reference.index;
  149. ref.offset:=paraloc.location^.reference.offset;
  150. a_load_const_ref(list,size,a,ref);
  151. end;
  152. else
  153. internalerror(2002081101);
  154. end;
  155. end;
  156. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);
  157. var
  158. tmpref, ref: treference;
  159. location: pcgparalocation;
  160. sizeleft: aint;
  161. begin
  162. location := paraloc.location;
  163. tmpref := r;
  164. sizeleft := paraloc.intsize;
  165. while assigned(location) do
  166. begin
  167. case location^.loc of
  168. LOC_REGISTER,LOC_CREGISTER:
  169. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  170. LOC_REFERENCE:
  171. begin
  172. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  173. { doubles in softemu mode have a strange order of registers and references }
  174. if location^.size=OS_32 then
  175. g_concatcopy(list,tmpref,ref,4)
  176. else
  177. begin
  178. g_concatcopy(list,tmpref,ref,sizeleft);
  179. if assigned(location^.next) then
  180. internalerror(2005010710);
  181. end;
  182. end;
  183. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  184. case location^.size of
  185. OS_F32, OS_F64:
  186. a_loadfpu_ref_reg(list,location^.size,tmpref,location^.register);
  187. else
  188. internalerror(2002072801);
  189. end;
  190. LOC_VOID:
  191. begin
  192. // nothing to do
  193. end;
  194. else
  195. internalerror(2002081103);
  196. end;
  197. inc(tmpref.offset,tcgsize2size[location^.size]);
  198. dec(sizeleft,tcgsize2size[location^.size]);
  199. location := location^.next;
  200. end;
  201. end;
  202. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);
  203. var
  204. ref: treference;
  205. tmpreg: tregister;
  206. begin
  207. paraloc.check_simple_location;
  208. case paraloc.location^.loc of
  209. LOC_REGISTER,LOC_CREGISTER:
  210. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  211. LOC_REFERENCE:
  212. begin
  213. reference_reset(ref);
  214. ref.base := paraloc.location^.reference.index;
  215. ref.offset := paraloc.location^.reference.offset;
  216. tmpreg := getintregister(list,OS_ADDR);
  217. a_loadaddr_ref_reg(list,r,tmpreg);
  218. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  219. end;
  220. else
  221. internalerror(2002080701);
  222. end;
  223. end;
  224. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  225. begin
  226. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  227. {
  228. the compiler does not properly set this flag anymore in pass 1, and
  229. for now we only need it after pass 2 (I hope) (JM)
  230. if not(pi_do_call in current_procinfo.flags) then
  231. internalerror(2003060703);
  232. }
  233. include(current_procinfo.flags,pi_do_call);
  234. end;
  235. procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
  236. var
  237. r : tregister;
  238. begin
  239. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  240. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  241. {
  242. the compiler does not properly set this flag anymore in pass 1, and
  243. for now we only need it after pass 2 (I hope) (JM)
  244. if not(pi_do_call in current_procinfo.flags) then
  245. internalerror(2003060703);
  246. }
  247. include(current_procinfo.flags,pi_do_call);
  248. end;
  249. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  250. begin
  251. a_op_const_reg_reg(list,op,size,a,reg,reg);
  252. end;
  253. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  254. begin
  255. case op of
  256. OP_NEG:
  257. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  258. OP_NOT:
  259. begin
  260. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  261. case size of
  262. OS_8 :
  263. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  264. OS_16 :
  265. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  266. end;
  267. end
  268. else
  269. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  270. end;
  271. end;
  272. const
  273. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  274. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  275. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  276. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  277. size: tcgsize; a: aint; src, dst: tregister);
  278. var
  279. ovloc : tlocation;
  280. begin
  281. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  282. end;
  283. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  284. size: tcgsize; src1, src2, dst: tregister);
  285. var
  286. ovloc : tlocation;
  287. begin
  288. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  289. end;
  290. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  291. var
  292. shift : byte;
  293. tmpreg : tregister;
  294. so : tshifterop;
  295. l1 : longint;
  296. begin
  297. ovloc.loc:=LOC_VOID;
  298. if is_shifter_const(-a,shift) then
  299. case op of
  300. OP_ADD:
  301. begin
  302. op:=OP_SUB;
  303. a:=dword(-a);
  304. end;
  305. OP_SUB:
  306. begin
  307. op:=OP_ADD;
  308. a:=dword(-a);
  309. end
  310. end;
  311. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  312. case op of
  313. OP_NEG,OP_NOT,
  314. OP_DIV,OP_IDIV:
  315. internalerror(200308281);
  316. OP_SHL:
  317. begin
  318. if a>32 then
  319. internalerror(200308291);
  320. if a<>0 then
  321. begin
  322. shifterop_reset(so);
  323. so.shiftmode:=SM_LSL;
  324. so.shiftimm:=a;
  325. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  326. end
  327. else
  328. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  329. end;
  330. OP_SHR:
  331. begin
  332. if a>32 then
  333. internalerror(200308292);
  334. shifterop_reset(so);
  335. if a<>0 then
  336. begin
  337. so.shiftmode:=SM_LSR;
  338. so.shiftimm:=a;
  339. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  340. end
  341. else
  342. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  343. end;
  344. OP_SAR:
  345. begin
  346. if a>32 then
  347. internalerror(200308291);
  348. if a<>0 then
  349. begin
  350. shifterop_reset(so);
  351. so.shiftmode:=SM_ASR;
  352. so.shiftimm:=a;
  353. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  354. end
  355. else
  356. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  357. end;
  358. else
  359. list.concat(setoppostfix(
  360. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  361. ));
  362. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  363. begin
  364. ovloc.loc:=LOC_FLAGS;
  365. case op of
  366. OP_ADD:
  367. ovloc.resflags:=F_CS;
  368. OP_SUB:
  369. ovloc.resflags:=F_CC;
  370. end;
  371. end;
  372. end
  373. else
  374. begin
  375. { there could be added some more sophisticated optimizations }
  376. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  377. a_load_reg_reg(list,size,size,src,dst)
  378. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  379. a_load_const_reg(list,size,0,dst)
  380. else if (op in [OP_IMUL]) and (a=-1) then
  381. a_op_reg_reg(list,OP_NEG,size,src,dst)
  382. { we do this here instead in the peephole optimizer because
  383. it saves us a register }
  384. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  385. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  386. else
  387. begin
  388. tmpreg:=getintregister(list,size);
  389. a_load_const_reg(list,size,a,tmpreg);
  390. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  391. end;
  392. end;
  393. end;
  394. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  395. var
  396. so : tshifterop;
  397. tmpreg,overflowreg : tregister;
  398. asmop : tasmop;
  399. begin
  400. ovloc.loc:=LOC_VOID;
  401. case op of
  402. OP_NEG,OP_NOT,
  403. OP_DIV,OP_IDIV:
  404. internalerror(200308281);
  405. OP_SHL:
  406. begin
  407. shifterop_reset(so);
  408. so.rs:=src1;
  409. so.shiftmode:=SM_LSL;
  410. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  411. end;
  412. OP_SHR:
  413. begin
  414. shifterop_reset(so);
  415. so.rs:=src1;
  416. so.shiftmode:=SM_LSR;
  417. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  418. end;
  419. OP_SAR:
  420. begin
  421. shifterop_reset(so);
  422. so.rs:=src1;
  423. so.shiftmode:=SM_ASR;
  424. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  425. end;
  426. OP_IMUL,
  427. OP_MUL:
  428. begin
  429. if cgsetflags or setflags then
  430. begin
  431. overflowreg:=getintregister(list,size);
  432. if op=OP_IMUL then
  433. asmop:=A_SMULL
  434. else
  435. asmop:=A_UMULL;
  436. { the arm doesn't allow that rd and rm are the same }
  437. if dst=src2 then
  438. begin
  439. if dst<>src1 then
  440. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  441. else
  442. begin
  443. tmpreg:=getintregister(list,size);
  444. a_load_reg_reg(list,size,size,src2,dst);
  445. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  446. end;
  447. end
  448. else
  449. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  450. if op=OP_IMUL then
  451. begin
  452. shifterop_reset(so);
  453. so.shiftmode:=SM_ASR;
  454. so.shiftimm:=31;
  455. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  456. end
  457. else
  458. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  459. ovloc.loc:=LOC_FLAGS;
  460. ovloc.resflags:=F_NE;
  461. end
  462. else
  463. begin
  464. { the arm doesn't allow that rd and rm are the same }
  465. if dst=src2 then
  466. begin
  467. if dst<>src1 then
  468. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  469. else
  470. begin
  471. tmpreg:=getintregister(list,size);
  472. a_load_reg_reg(list,size,size,src2,dst);
  473. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  474. end;
  475. end
  476. else
  477. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  478. end;
  479. end;
  480. else
  481. list.concat(setoppostfix(
  482. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  483. ));
  484. end;
  485. end;
  486. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);
  487. var
  488. imm_shift : byte;
  489. l : tasmlabel;
  490. hr : treference;
  491. begin
  492. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  493. internalerror(2002090902);
  494. if is_shifter_const(a,imm_shift) then
  495. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  496. else if is_shifter_const(not(a),imm_shift) then
  497. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  498. else
  499. begin
  500. reference_reset(hr);
  501. objectlibrary.getjumplabel(l);
  502. cg.a_label(current_procinfo.aktlocaldata,l);
  503. hr.symboldata:=current_procinfo.aktlocaldata.last;
  504. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  505. hr.symbol:=l;
  506. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  507. end;
  508. end;
  509. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  510. var
  511. tmpreg : tregister;
  512. tmpref : treference;
  513. l : tasmlabel;
  514. begin
  515. tmpreg:=NR_NO;
  516. { Be sure to have a base register }
  517. if (ref.base=NR_NO) then
  518. begin
  519. if ref.shiftmode<>SM_None then
  520. internalerror(200308294);
  521. ref.base:=ref.index;
  522. ref.index:=NR_NO;
  523. end;
  524. { absolute symbols can't be handled directly, we've to store the symbol reference
  525. in the text segment and access it pc relative
  526. For now, we assume that references where base or index equals to PC are already
  527. relative, all other references are assumed to be absolute and thus they need
  528. to be handled extra.
  529. A proper solution would be to change refoptions to a set and store the information
  530. if the symbol is absolute or relative there.
  531. }
  532. if (assigned(ref.symbol) and
  533. not(is_pc(ref.base)) and
  534. not(is_pc(ref.index))
  535. ) or
  536. { [#xxx] isn't a valid address operand }
  537. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  538. (ref.offset<-4095) or
  539. (ref.offset>4095) or
  540. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  541. ((ref.offset<-255) or
  542. (ref.offset>255)
  543. )
  544. ) or
  545. ((op in [A_LDF,A_STF]) and
  546. ((ref.offset<-1020) or
  547. (ref.offset>1020) or
  548. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  549. assigned(ref.symbol)
  550. )
  551. ) then
  552. begin
  553. reference_reset(tmpref);
  554. { load symbol }
  555. tmpreg:=getintregister(list,OS_INT);
  556. if assigned(ref.symbol) then
  557. begin
  558. objectlibrary.getjumplabel(l);
  559. cg.a_label(current_procinfo.aktlocaldata,l);
  560. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  561. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  562. { load consts entry }
  563. tmpref.symbol:=l;
  564. tmpref.base:=NR_R15;
  565. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  566. end
  567. else
  568. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  569. if (ref.base<>NR_NO) then
  570. begin
  571. if ref.index<>NR_NO then
  572. begin
  573. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  574. ref.base:=tmpreg;
  575. end
  576. else
  577. begin
  578. ref.index:=tmpreg;
  579. ref.shiftimm:=0;
  580. ref.signindex:=1;
  581. ref.shiftmode:=SM_None;
  582. end;
  583. end
  584. else
  585. ref.base:=tmpreg;
  586. ref.offset:=0;
  587. ref.symbol:=nil;
  588. end;
  589. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  590. begin
  591. if tmpreg<>NR_NO then
  592. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  593. else
  594. begin
  595. tmpreg:=getintregister(list,OS_ADDR);
  596. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  597. ref.base:=tmpreg;
  598. end;
  599. ref.offset:=0;
  600. end;
  601. { floating point operations have only limited references
  602. we expect here, that a base is already set }
  603. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  604. begin
  605. if ref.shiftmode<>SM_none then
  606. internalerror(200309121);
  607. if tmpreg<>NR_NO then
  608. begin
  609. if ref.base=tmpreg then
  610. begin
  611. if ref.signindex<0 then
  612. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  613. else
  614. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  615. ref.index:=NR_NO;
  616. end
  617. else
  618. begin
  619. if ref.index<>tmpreg then
  620. internalerror(200403161);
  621. if ref.signindex<0 then
  622. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  623. else
  624. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  625. ref.base:=tmpreg;
  626. ref.index:=NR_NO;
  627. end;
  628. end
  629. else
  630. begin
  631. tmpreg:=getintregister(list,OS_ADDR);
  632. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  633. ref.base:=tmpreg;
  634. ref.index:=NR_NO;
  635. end;
  636. end;
  637. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  638. end;
  639. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  640. var
  641. oppostfix:toppostfix;
  642. begin
  643. case ToSize of
  644. { signed integer registers }
  645. OS_8,
  646. OS_S8:
  647. oppostfix:=PF_B;
  648. OS_16,
  649. OS_S16:
  650. oppostfix:=PF_H;
  651. OS_32,
  652. OS_S32:
  653. oppostfix:=PF_None;
  654. else
  655. InternalError(200308295);
  656. end;
  657. handle_load_store(list,A_STR,oppostfix,reg,ref);
  658. end;
  659. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  660. var
  661. oppostfix:toppostfix;
  662. begin
  663. case FromSize of
  664. { signed integer registers }
  665. OS_8:
  666. oppostfix:=PF_B;
  667. OS_S8:
  668. oppostfix:=PF_SB;
  669. OS_16:
  670. oppostfix:=PF_H;
  671. OS_S16:
  672. oppostfix:=PF_SH;
  673. OS_32,
  674. OS_S32:
  675. oppostfix:=PF_None;
  676. else
  677. InternalError(200308291);
  678. end;
  679. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  680. end;
  681. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  682. var
  683. instr: taicpu;
  684. so : tshifterop;
  685. begin
  686. shifterop_reset(so);
  687. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  688. (
  689. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  690. (tosize <> fromsize) and
  691. not(fromsize in [OS_32,OS_S32])
  692. ) then
  693. begin
  694. case tosize of
  695. OS_8:
  696. list.concat(taicpu.op_reg_reg_const(A_AND,
  697. reg2,reg1,$ff));
  698. OS_S8:
  699. begin
  700. so.shiftmode:=SM_LSL;
  701. so.shiftimm:=24;
  702. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  703. so.shiftmode:=SM_ASR;
  704. so.shiftimm:=24;
  705. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  706. end;
  707. OS_16:
  708. begin
  709. so.shiftmode:=SM_LSL;
  710. so.shiftimm:=16;
  711. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  712. so.shiftmode:=SM_LSR;
  713. so.shiftimm:=16;
  714. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  715. end;
  716. OS_S16:
  717. begin
  718. so.shiftmode:=SM_LSL;
  719. so.shiftimm:=16;
  720. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  721. so.shiftmode:=SM_ASR;
  722. so.shiftimm:=16;
  723. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  724. end;
  725. OS_32,OS_S32:
  726. begin
  727. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  728. list.concat(instr);
  729. add_move_instruction(instr);
  730. end;
  731. else internalerror(2002090901);
  732. end;
  733. end
  734. else
  735. begin
  736. if reg1<>reg2 then
  737. begin
  738. { same size, only a register mov required }
  739. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  740. list.Concat(instr);
  741. { Notify the register allocator that we have written a move instruction so
  742. it can try to eliminate it. }
  743. add_move_instruction(instr);
  744. end;
  745. end;
  746. end;
  747. procedure tcgarm.a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  748. var
  749. href,href2 : treference;
  750. hloc : pcgparalocation;
  751. begin
  752. href:=ref;
  753. hloc:=paraloc.location;
  754. while assigned(hloc) do
  755. begin
  756. case hloc^.loc of
  757. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  758. a_loadfpu_ref_reg(list,size,ref,hloc^.register);
  759. LOC_REGISTER :
  760. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  761. LOC_REFERENCE :
  762. begin
  763. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  764. a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2);
  765. end;
  766. else
  767. internalerror(200408241);
  768. end;
  769. inc(href.offset,tcgsize2size[hloc^.size]);
  770. hloc:=hloc^.next;
  771. end;
  772. end;
  773. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  774. begin
  775. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  776. end;
  777. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  778. var
  779. oppostfix:toppostfix;
  780. begin
  781. case size of
  782. OS_F32:
  783. oppostfix:=PF_S;
  784. OS_F64:
  785. oppostfix:=PF_D;
  786. OS_F80:
  787. oppostfix:=PF_E;
  788. else
  789. InternalError(200309021);
  790. end;
  791. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  792. end;
  793. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  794. var
  795. oppostfix:toppostfix;
  796. begin
  797. case size of
  798. OS_F32:
  799. oppostfix:=PF_S;
  800. OS_F64:
  801. oppostfix:=PF_D;
  802. OS_F80:
  803. oppostfix:=PF_E;
  804. else
  805. InternalError(200309022);
  806. end;
  807. handle_load_store(list,A_STF,oppostfix,reg,ref);
  808. end;
  809. { comparison operations }
  810. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  811. l : tasmlabel);
  812. var
  813. tmpreg : tregister;
  814. b : byte;
  815. begin
  816. if is_shifter_const(a,b) then
  817. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  818. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  819. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  820. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  821. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  822. else
  823. begin
  824. tmpreg:=getintregister(list,size);
  825. a_load_const_reg(list,size,a,tmpreg);
  826. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  827. end;
  828. a_jmp_cond(list,cmp_op,l);
  829. end;
  830. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  831. begin
  832. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  833. a_jmp_cond(list,cmp_op,l);
  834. end;
  835. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  836. begin
  837. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  838. end;
  839. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  840. begin
  841. list.concat(taicpu.op_sym(A_B,l));
  842. end;
  843. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  844. var
  845. ai : taicpu;
  846. begin
  847. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  848. ai.is_jmp:=true;
  849. list.concat(ai);
  850. end;
  851. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  852. var
  853. ai : taicpu;
  854. begin
  855. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  856. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  857. end;
  858. procedure tcgarm.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);
  859. var
  860. ref : treference;
  861. shift : byte;
  862. firstfloatreg,lastfloatreg,
  863. r : byte;
  864. begin
  865. LocalSize:=align(LocalSize,4);
  866. if not(nostackframe) then
  867. begin
  868. firstfloatreg:=RS_NO;
  869. { save floating point registers? }
  870. for r:=RS_F0 to RS_F7 do
  871. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  872. begin
  873. if firstfloatreg=RS_NO then
  874. firstfloatreg:=r;
  875. lastfloatreg:=r;
  876. end;
  877. a_reg_alloc(list,NR_STACK_POINTER_REG);
  878. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  879. a_reg_alloc(list,NR_R12);
  880. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  881. { save int registers }
  882. reference_reset(ref);
  883. ref.index:=NR_STACK_POINTER_REG;
  884. ref.addressmode:=AM_PREINDEXED;
  885. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  886. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  887. PF_FD));
  888. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  889. { allocate necessary stack size }
  890. { don't use a_op_const_reg_reg here because we don't allow register allocations
  891. in the entry/exit code }
  892. if not(is_shifter_const(localsize,shift)) then
  893. begin
  894. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  895. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  896. a_reg_dealloc(list,NR_R12);
  897. end
  898. else
  899. begin
  900. a_reg_dealloc(list,NR_R12);
  901. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  902. end;
  903. if firstfloatreg<>RS_NO then
  904. begin
  905. reference_reset(ref);
  906. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  907. begin
  908. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  909. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  910. ref.base:=NR_R12;
  911. end
  912. else
  913. begin
  914. ref.base:=NR_FRAME_POINTER_REG;
  915. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  916. end;
  917. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  918. lastfloatreg-firstfloatreg+1,ref));
  919. end;
  920. end;
  921. end;
  922. procedure tcgarm.g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean);
  923. var
  924. ref : treference;
  925. firstfloatreg,lastfloatreg,
  926. r : byte;
  927. shift : byte;
  928. begin
  929. if not(nostackframe) then
  930. begin
  931. { restore floating point register }
  932. firstfloatreg:=RS_NO;
  933. { save floating point registers? }
  934. for r:=RS_F0 to RS_F7 do
  935. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  936. begin
  937. if firstfloatreg=RS_NO then
  938. firstfloatreg:=r;
  939. lastfloatreg:=r;
  940. end;
  941. if firstfloatreg<>RS_NO then
  942. begin
  943. reference_reset(ref);
  944. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  945. begin
  946. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  947. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  948. ref.base:=NR_R12;
  949. end
  950. else
  951. begin
  952. ref.base:=NR_FRAME_POINTER_REG;
  953. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  954. end;
  955. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  956. lastfloatreg-firstfloatreg+1,ref));
  957. end;
  958. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  959. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  960. else
  961. begin
  962. { restore int registers and return }
  963. reference_reset(ref);
  964. ref.index:=NR_FRAME_POINTER_REG;
  965. 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));
  966. end;
  967. end
  968. else
  969. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  970. end;
  971. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  972. var
  973. b : byte;
  974. tmpref : treference;
  975. instr : taicpu;
  976. begin
  977. if ref.addressmode<>AM_OFFSET then
  978. internalerror(200309071);
  979. tmpref:=ref;
  980. { Be sure to have a base register }
  981. if (tmpref.base=NR_NO) then
  982. begin
  983. if tmpref.shiftmode<>SM_None then
  984. internalerror(200308294);
  985. if tmpref.signindex<0 then
  986. internalerror(200312023);
  987. tmpref.base:=tmpref.index;
  988. tmpref.index:=NR_NO;
  989. end;
  990. if assigned(tmpref.symbol) or
  991. not((is_shifter_const(tmpref.offset,b)) or
  992. (is_shifter_const(-tmpref.offset,b))
  993. ) then
  994. fixref(list,tmpref);
  995. { expect a base here if there is an index }
  996. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  997. internalerror(200312022);
  998. if tmpref.index<>NR_NO then
  999. begin
  1000. if tmpref.shiftmode<>SM_None then
  1001. internalerror(200312021);
  1002. if tmpref.signindex<0 then
  1003. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1004. else
  1005. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1006. if tmpref.offset<>0 then
  1007. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1008. end
  1009. else
  1010. begin
  1011. if tmpref.offset<>0 then
  1012. begin
  1013. if tmpref.base<>NR_NO then
  1014. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1015. else
  1016. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  1017. end
  1018. else
  1019. begin
  1020. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1021. list.concat(instr);
  1022. add_move_instruction(instr);
  1023. end;
  1024. end;
  1025. end;
  1026. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  1027. var
  1028. tmpreg : tregister;
  1029. tmpref : treference;
  1030. l : tasmlabel;
  1031. begin
  1032. { absolute symbols can't be handled directly, we've to store the symbol reference
  1033. in the text segment and access it pc relative
  1034. For now, we assume that references where base or index equals to PC are already
  1035. relative, all other references are assumed to be absolute and thus they need
  1036. to be handled extra.
  1037. A proper solution would be to change refoptions to a set and store the information
  1038. if the symbol is absolute or relative there.
  1039. }
  1040. { create consts entry }
  1041. reference_reset(tmpref);
  1042. objectlibrary.getjumplabel(l);
  1043. cg.a_label(current_procinfo.aktlocaldata,l);
  1044. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1045. if assigned(ref.symbol) then
  1046. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1047. else
  1048. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1049. { load consts entry }
  1050. tmpreg:=getintregister(list,OS_INT);
  1051. tmpref.symbol:=l;
  1052. tmpref.base:=NR_PC;
  1053. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1054. if (ref.base<>NR_NO) then
  1055. begin
  1056. if ref.index<>NR_NO then
  1057. begin
  1058. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1059. ref.base:=tmpreg;
  1060. end
  1061. else
  1062. begin
  1063. ref.index:=tmpreg;
  1064. ref.shiftimm:=0;
  1065. ref.signindex:=1;
  1066. ref.shiftmode:=SM_None;
  1067. end;
  1068. end
  1069. else
  1070. ref.base:=tmpreg;
  1071. ref.offset:=0;
  1072. ref.symbol:=nil;
  1073. end;
  1074. procedure tcgarm.g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  1075. var
  1076. paraloc1,paraloc2,paraloc3 : TCGPara;
  1077. begin
  1078. paraloc1.init;
  1079. paraloc2.init;
  1080. paraloc3.init;
  1081. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1082. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1083. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1084. paramanager.allocparaloc(list,paraloc3);
  1085. a_param_const(list,OS_INT,len,paraloc3);
  1086. paramanager.allocparaloc(list,paraloc2);
  1087. a_paramaddr_ref(list,dest,paraloc2);
  1088. paramanager.allocparaloc(list,paraloc2);
  1089. a_paramaddr_ref(list,source,paraloc1);
  1090. paramanager.freeparaloc(list,paraloc3);
  1091. paramanager.freeparaloc(list,paraloc2);
  1092. paramanager.freeparaloc(list,paraloc1);
  1093. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1094. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1095. a_call_name(list,'FPC_MOVE');
  1096. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1097. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1098. paraloc3.done;
  1099. paraloc2.done;
  1100. paraloc1.done;
  1101. end;
  1102. procedure tcgarm.g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  1103. var
  1104. srcref,dstref:treference;
  1105. srcreg,destreg,countreg,r:tregister;
  1106. helpsize:aword;
  1107. copysize:byte;
  1108. cgsize:Tcgsize;
  1109. procedure genloop(count : aword;size : byte);
  1110. const
  1111. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1112. var
  1113. l : tasmlabel;
  1114. begin
  1115. objectlibrary.getjumplabel(l);
  1116. a_load_const_reg(list,OS_INT,count,countreg);
  1117. cg.a_label(list,l);
  1118. srcref.addressmode:=AM_POSTINDEXED;
  1119. dstref.addressmode:=AM_POSTINDEXED;
  1120. srcref.offset:=size;
  1121. dstref.offset:=size;
  1122. r:=getintregister(list,size2opsize[size]);
  1123. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1124. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1125. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1126. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  1127. { keep the registers alive }
  1128. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1129. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1130. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1131. end;
  1132. begin
  1133. if len=0 then
  1134. exit;
  1135. helpsize:=12;
  1136. dstref:=dest;
  1137. srcref:=source;
  1138. if cs_littlesize in aktglobalswitches then
  1139. helpsize:=8;
  1140. if (len<=helpsize) and aligned then
  1141. begin
  1142. copysize:=4;
  1143. cgsize:=OS_32;
  1144. while len<>0 do
  1145. begin
  1146. if len<2 then
  1147. begin
  1148. copysize:=1;
  1149. cgsize:=OS_8;
  1150. end
  1151. else if len<4 then
  1152. begin
  1153. copysize:=2;
  1154. cgsize:=OS_16;
  1155. end;
  1156. dec(len,copysize);
  1157. r:=getintregister(list,cgsize);
  1158. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1159. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1160. inc(srcref.offset,copysize);
  1161. inc(dstref.offset,copysize);
  1162. end;
  1163. end
  1164. else
  1165. begin
  1166. destreg:=getintregister(list,OS_ADDR);
  1167. a_loadaddr_ref_reg(list,dest,destreg);
  1168. reference_reset_base(dstref,destreg,0);
  1169. srcreg:=getintregister(list,OS_ADDR);
  1170. a_loadaddr_ref_reg(list,source,srcreg);
  1171. reference_reset_base(srcref,srcreg,0);
  1172. countreg:=getintregister(list,OS_32);
  1173. // if cs_littlesize in aktglobalswitches then
  1174. genloop(len,1);
  1175. {
  1176. else
  1177. begin
  1178. helpsize:=len shr 2;
  1179. len:=len and 3;
  1180. if helpsize>1 then
  1181. begin
  1182. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1183. list.concat(Taicpu.op_none(A_REP,S_NO));
  1184. end;
  1185. if helpsize>0 then
  1186. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1187. if len>1 then
  1188. begin
  1189. dec(len,2);
  1190. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1191. end;
  1192. if len=1 then
  1193. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1194. end;
  1195. }
  1196. end;
  1197. end;
  1198. procedure tcgarm.g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);
  1199. begin
  1200. g_concatcopy_internal(list,source,dest,len,false);
  1201. end;
  1202. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);
  1203. begin
  1204. g_concatcopy_internal(list,source,dest,len,true);
  1205. end;
  1206. procedure tcgarm.g_overflowCheck(list : taasmoutput;const l : tlocation;def : tdef);
  1207. var
  1208. ovloc : tlocation;
  1209. begin
  1210. ovloc.loc:=LOC_VOID;
  1211. g_overflowCheck_loc(list,l,def,ovloc);
  1212. end;
  1213. procedure tcgarm.g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1214. var
  1215. hl : tasmlabel;
  1216. ai:TAiCpu;
  1217. hflags : tresflags;
  1218. begin
  1219. if not(cs_check_overflow in aktlocalswitches) then
  1220. exit;
  1221. objectlibrary.getjumplabel(hl);
  1222. case ovloc.loc of
  1223. LOC_VOID:
  1224. begin
  1225. ai:=taicpu.op_sym(A_B,hl);
  1226. ai.is_jmp:=true;
  1227. if not((def.deftype=pointerdef) or
  1228. ((def.deftype=orddef) and
  1229. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1230. ai.SetCondition(C_VC)
  1231. else
  1232. ai.SetCondition(C_CC);
  1233. list.concat(ai);
  1234. end;
  1235. LOC_FLAGS:
  1236. begin
  1237. hflags:=ovloc.resflags;
  1238. inverse_flags(hflags);
  1239. cg.a_jmp_flags(list,hflags,hl);
  1240. end;
  1241. else
  1242. internalerror(200409281);
  1243. end;
  1244. a_call_name(list,'FPC_OVERFLOW');
  1245. a_label(list,hl);
  1246. end;
  1247. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1248. begin
  1249. { this work is done in g_proc_entry }
  1250. end;
  1251. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1252. begin
  1253. { this work is done in g_proc_exit }
  1254. end;
  1255. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1256. var
  1257. ai : taicpu;
  1258. begin
  1259. ai:=Taicpu.Op_sym(A_B,l);
  1260. ai.SetCondition(OpCmp2AsmCond[cond]);
  1261. ai.is_jmp:=true;
  1262. list.concat(ai);
  1263. end;
  1264. procedure tcgarm.g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  1265. procedure loadvmttor12;
  1266. var
  1267. href : treference;
  1268. begin
  1269. reference_reset_base(href,NR_R0,0);
  1270. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1271. end;
  1272. procedure op_onr12methodaddr;
  1273. var
  1274. href : treference;
  1275. begin
  1276. if (procdef.extnumber=$ffff) then
  1277. Internalerror(200006139);
  1278. { call/jmp vmtoffs(%eax) ; method offs }
  1279. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1280. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1281. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1282. end;
  1283. var
  1284. lab : tasmsymbol;
  1285. make_global : boolean;
  1286. href : treference;
  1287. begin
  1288. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1289. Internalerror(200006137);
  1290. if not assigned(procdef._class) or
  1291. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1292. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1293. Internalerror(200006138);
  1294. if procdef.owner.symtabletype<>objectsymtable then
  1295. Internalerror(200109191);
  1296. make_global:=false;
  1297. if (not current_module.is_unit) or
  1298. (cs_create_smart in aktmoduleswitches) or
  1299. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1300. make_global:=true;
  1301. if make_global then
  1302. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1303. else
  1304. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1305. { set param1 interface to self }
  1306. g_adjust_self_value(list,procdef,ioffset);
  1307. { case 4 }
  1308. if po_virtualmethod in procdef.procoptions then
  1309. begin
  1310. loadvmttor12;
  1311. op_onr12methodaddr;
  1312. end
  1313. { case 0 }
  1314. else
  1315. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION)));
  1316. list.concat(Tai_symbol_end.Createname(labelname));
  1317. end;
  1318. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1319. var
  1320. tmpreg : tregister;
  1321. begin
  1322. case op of
  1323. OP_NEG:
  1324. begin
  1325. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1326. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1327. end;
  1328. OP_NOT:
  1329. begin
  1330. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1331. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1332. end;
  1333. else
  1334. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1335. end;
  1336. end;
  1337. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1338. begin
  1339. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1340. end;
  1341. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1342. var
  1343. ovloc : tlocation;
  1344. begin
  1345. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1346. end;
  1347. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1348. var
  1349. ovloc : tlocation;
  1350. begin
  1351. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1352. end;
  1353. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1354. var
  1355. tmpreg : tregister;
  1356. b : byte;
  1357. begin
  1358. ovloc.loc:=LOC_VOID;
  1359. case op of
  1360. OP_NEG,
  1361. OP_NOT :
  1362. internalerror(200306017);
  1363. end;
  1364. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1365. begin
  1366. case op of
  1367. OP_ADD:
  1368. begin
  1369. if is_shifter_const(lo(value),b) then
  1370. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1371. else
  1372. begin
  1373. tmpreg:=cg.getintregister(list,OS_32);
  1374. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1375. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1376. end;
  1377. if is_shifter_const(hi(value),b) then
  1378. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1379. else
  1380. begin
  1381. tmpreg:=cg.getintregister(list,OS_32);
  1382. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1383. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1384. end;
  1385. end;
  1386. OP_SUB:
  1387. begin
  1388. if is_shifter_const(lo(value),b) then
  1389. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1390. else
  1391. begin
  1392. tmpreg:=cg.getintregister(list,OS_32);
  1393. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1394. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1395. end;
  1396. if is_shifter_const(hi(value),b) then
  1397. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1398. else
  1399. begin
  1400. tmpreg:=cg.getintregister(list,OS_32);
  1401. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1402. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1403. end;
  1404. end;
  1405. else
  1406. internalerror(200502131);
  1407. end;
  1408. if size=OS_64 then
  1409. begin
  1410. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1411. ovloc.loc:=LOC_FLAGS;
  1412. case op of
  1413. OP_ADD:
  1414. ovloc.resflags:=F_CS;
  1415. OP_SUB:
  1416. ovloc.resflags:=F_CC;
  1417. end;
  1418. end;
  1419. end
  1420. else
  1421. begin
  1422. case op of
  1423. OP_AND,OP_OR,OP_XOR:
  1424. begin
  1425. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1426. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1427. end;
  1428. OP_ADD:
  1429. begin
  1430. if is_shifter_const(lo(value),b) then
  1431. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1432. else
  1433. begin
  1434. tmpreg:=cg.getintregister(list,OS_32);
  1435. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1436. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1437. end;
  1438. if is_shifter_const(hi(value),b) then
  1439. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1440. else
  1441. begin
  1442. tmpreg:=cg.getintregister(list,OS_32);
  1443. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1444. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1445. end;
  1446. end;
  1447. OP_SUB:
  1448. begin
  1449. if is_shifter_const(lo(value),b) then
  1450. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1451. else
  1452. begin
  1453. tmpreg:=cg.getintregister(list,OS_32);
  1454. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1455. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1456. end;
  1457. if is_shifter_const(hi(value),b) then
  1458. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1459. else
  1460. begin
  1461. tmpreg:=cg.getintregister(list,OS_32);
  1462. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1463. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1464. end;
  1465. end;
  1466. else
  1467. internalerror(2003083101);
  1468. end;
  1469. end;
  1470. end;
  1471. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1472. var
  1473. op1,op2:TAsmOp;
  1474. begin
  1475. ovloc.loc:=LOC_VOID;
  1476. case op of
  1477. OP_NEG,
  1478. OP_NOT :
  1479. internalerror(200306017);
  1480. end;
  1481. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1482. begin
  1483. case op of
  1484. OP_ADD:
  1485. begin
  1486. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1487. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1488. end;
  1489. OP_SUB:
  1490. begin
  1491. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1492. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1493. end;
  1494. else
  1495. internalerror(2003083101);
  1496. end;
  1497. if size=OS_64 then
  1498. begin
  1499. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1500. ovloc.loc:=LOC_FLAGS;
  1501. case op of
  1502. OP_ADD:
  1503. ovloc.resflags:=F_CC;
  1504. OP_SUB:
  1505. ovloc.resflags:=F_CS;
  1506. end;
  1507. end;
  1508. end
  1509. else
  1510. begin
  1511. case op of
  1512. OP_AND,OP_OR,OP_XOR:
  1513. begin
  1514. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1515. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1516. end;
  1517. OP_ADD:
  1518. begin
  1519. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1520. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1521. end;
  1522. OP_SUB:
  1523. begin
  1524. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1525. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1526. end;
  1527. else
  1528. internalerror(2003083101);
  1529. end;
  1530. end;
  1531. end;
  1532. begin
  1533. cg:=tcgarm.create;
  1534. cg64:=tcg64farm.create;
  1535. end.