cgcpu.pas 63 KB

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