cgcpu.pas 63 KB

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