n386add.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Code generation for add nodes on the i386
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit n386add;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nadd,cpubase,nx86add;
  22. type
  23. ti386addnode = class(tx86addnode)
  24. procedure second_add64bit;override;
  25. procedure second_cmp64bit;override;
  26. procedure second_mul;override;
  27. end;
  28. implementation
  29. uses
  30. globtype,systems,
  31. cutils,verbose,globals,
  32. symconst,symdef,paramgr,
  33. aasmbase,aasmtai,aasmdata,aasmcpu,
  34. cgbase,procinfo,
  35. ncon,nset,cgutils,tgobj,
  36. cga,ncgutil,cgobj,cg64f32;
  37. {*****************************************************************************
  38. Add64bit
  39. *****************************************************************************}
  40. procedure ti386addnode.second_add64bit;
  41. var
  42. op : TOpCG;
  43. op1,op2 : TAsmOp;
  44. opsize : TOpSize;
  45. hregister,
  46. hregister2 : tregister;
  47. hl4 : tasmlabel;
  48. mboverflow,
  49. unsigned:boolean;
  50. r:Tregister;
  51. begin
  52. firstcomplex(self);
  53. pass_left_right;
  54. op1:=A_NONE;
  55. op2:=A_NONE;
  56. mboverflow:=false;
  57. opsize:=S_L;
  58. unsigned:=((left.resultdef.typ=orddef) and
  59. (torddef(left.resultdef).ordtype=u64bit)) or
  60. ((right.resultdef.typ=orddef) and
  61. (torddef(right.resultdef).ordtype=u64bit));
  62. case nodetype of
  63. addn :
  64. begin
  65. op:=OP_ADD;
  66. mboverflow:=true;
  67. end;
  68. subn :
  69. begin
  70. op:=OP_SUB;
  71. op1:=A_SUB;
  72. op2:=A_SBB;
  73. mboverflow:=true;
  74. end;
  75. xorn:
  76. op:=OP_XOR;
  77. orn:
  78. op:=OP_OR;
  79. andn:
  80. op:=OP_AND;
  81. else
  82. begin
  83. { everything should be handled in pass_1 (JM) }
  84. internalerror(200109051);
  85. end;
  86. end;
  87. { left and right no register? }
  88. { then one must be demanded }
  89. if (left.location.loc<>LOC_REGISTER) then
  90. begin
  91. if (right.location.loc<>LOC_REGISTER) then
  92. begin
  93. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  94. hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  95. cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
  96. location_reset(left.location,LOC_REGISTER,OS_64);
  97. left.location.register64.reglo:=hregister;
  98. left.location.register64.reghi:=hregister2;
  99. end
  100. else
  101. begin
  102. location_swap(left.location,right.location);
  103. toggleflag(nf_swapped);
  104. end;
  105. end;
  106. { at this point, left.location.loc should be LOC_REGISTER }
  107. if right.location.loc=LOC_REGISTER then
  108. begin
  109. { when swapped another result register }
  110. if (nodetype=subn) and (nf_swapped in flags) then
  111. begin
  112. cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
  113. left.location.register64,
  114. right.location.register64);
  115. location_swap(left.location,right.location);
  116. toggleflag(nf_swapped);
  117. end
  118. else
  119. begin
  120. cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
  121. right.location.register64,
  122. left.location.register64);
  123. end;
  124. end
  125. else
  126. begin
  127. { right.location<>LOC_REGISTER }
  128. if (nodetype=subn) and (nf_swapped in flags) then
  129. begin
  130. r:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  131. cg64.a_load64low_loc_reg(current_asmdata.CurrAsmList,right.location,r);
  132. emit_reg_reg(op1,opsize,left.location.register64.reglo,r);
  133. emit_reg_reg(A_MOV,opsize,r,left.location.register64.reglo);
  134. cg64.a_load64high_loc_reg(current_asmdata.CurrAsmList,right.location,r);
  135. { the carry flag is still ok }
  136. emit_reg_reg(op2,opsize,left.location.register64.reghi,r);
  137. emit_reg_reg(A_MOV,opsize,r,left.location.register64.reghi);
  138. end
  139. else
  140. begin
  141. cg64.a_op64_loc_reg(current_asmdata.CurrAsmList,op,location.size,right.location,
  142. left.location.register64);
  143. end;
  144. location_freetemp(current_asmdata.CurrAsmList,right.location);
  145. end;
  146. { only in case of overflow operations }
  147. { produce overflow code }
  148. { we must put it here directly, because sign of operation }
  149. { is in unsigned VAR!! }
  150. if mboverflow then
  151. begin
  152. if cs_check_overflow in current_settings.localswitches then
  153. begin
  154. current_asmdata.getjumplabel(hl4);
  155. if unsigned then
  156. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4)
  157. else
  158. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl4);
  159. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW');
  160. cg.a_label(current_asmdata.CurrAsmList,hl4);
  161. end;
  162. end;
  163. location_copy(location,left.location);
  164. end;
  165. procedure ti386addnode.second_cmp64bit;
  166. var
  167. hregister,
  168. hregister2 : tregister;
  169. href : treference;
  170. unsigned : boolean;
  171. procedure firstjmp64bitcmp;
  172. var
  173. oldnodetype : tnodetype;
  174. begin
  175. {$ifdef OLDREGVARS}
  176. load_all_regvars(current_asmdata.CurrAsmList);
  177. {$endif OLDREGVARS}
  178. { the jump the sequence is a little bit hairy }
  179. case nodetype of
  180. ltn,gtn:
  181. begin
  182. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  183. { cheat a little bit for the negative test }
  184. toggleflag(nf_swapped);
  185. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  186. toggleflag(nf_swapped);
  187. end;
  188. lten,gten:
  189. begin
  190. oldnodetype:=nodetype;
  191. if nodetype=lten then
  192. nodetype:=ltn
  193. else
  194. nodetype:=gtn;
  195. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
  196. { cheat for the negative test }
  197. if nodetype=ltn then
  198. nodetype:=gtn
  199. else
  200. nodetype:=ltn;
  201. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
  202. nodetype:=oldnodetype;
  203. end;
  204. equaln:
  205. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  206. unequaln:
  207. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  208. end;
  209. end;
  210. procedure secondjmp64bitcmp;
  211. begin
  212. { the jump the sequence is a little bit hairy }
  213. case nodetype of
  214. ltn,gtn,lten,gten:
  215. begin
  216. { the comparisaion of the low dword have to be }
  217. { always unsigned! }
  218. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
  219. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  220. end;
  221. equaln:
  222. begin
  223. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
  224. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  225. end;
  226. unequaln:
  227. begin
  228. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
  229. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  230. end;
  231. end;
  232. end;
  233. begin
  234. firstcomplex(self);
  235. pass_left_right;
  236. unsigned:=((left.resultdef.typ=orddef) and
  237. (torddef(left.resultdef).ordtype=u64bit)) or
  238. ((right.resultdef.typ=orddef) and
  239. (torddef(right.resultdef).ordtype=u64bit));
  240. { left and right no register? }
  241. { then one must be demanded }
  242. if (left.location.loc<>LOC_REGISTER) then
  243. begin
  244. if (right.location.loc<>LOC_REGISTER) then
  245. begin
  246. { we can reuse a CREGISTER for comparison }
  247. if (left.location.loc<>LOC_CREGISTER) then
  248. begin
  249. hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  250. hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  251. cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
  252. location_reset(left.location,LOC_REGISTER,OS_64);
  253. left.location.register64.reglo:=hregister;
  254. left.location.register64.reghi:=hregister2;
  255. end;
  256. end
  257. else
  258. begin
  259. location_swap(left.location,right.location);
  260. toggleflag(nf_swapped);
  261. end;
  262. end;
  263. { at this point, left.location.loc should be LOC_REGISTER }
  264. if right.location.loc=LOC_REGISTER then
  265. begin
  266. emit_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi);
  267. firstjmp64bitcmp;
  268. emit_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo);
  269. secondjmp64bitcmp;
  270. end
  271. else
  272. begin
  273. case right.location.loc of
  274. LOC_CREGISTER :
  275. begin
  276. emit_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi);
  277. firstjmp64bitcmp;
  278. emit_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo);
  279. secondjmp64bitcmp;
  280. end;
  281. LOC_CREFERENCE,
  282. LOC_REFERENCE :
  283. begin
  284. href:=right.location.reference;
  285. inc(href.offset,4);
  286. emit_ref_reg(A_CMP,S_L,href,left.location.register64.reghi);
  287. firstjmp64bitcmp;
  288. emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.register64.reglo);
  289. secondjmp64bitcmp;
  290. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  291. location_freetemp(current_asmdata.CurrAsmList,right.location);
  292. end;
  293. LOC_CONSTANT :
  294. begin
  295. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(hi(right.location.value64)),left.location.register64.reghi));
  296. firstjmp64bitcmp;
  297. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(lo(right.location.value64)),left.location.register64.reglo));
  298. secondjmp64bitcmp;
  299. end;
  300. else
  301. internalerror(200203282);
  302. end;
  303. end;
  304. location_freetemp(current_asmdata.CurrAsmList,left.location);
  305. { we have LOC_JUMP as result }
  306. location_reset(location,LOC_JUMP,OS_NO)
  307. end;
  308. {*****************************************************************************
  309. x86 MUL
  310. *****************************************************************************}
  311. procedure ti386addnode.second_mul;
  312. var r:Tregister;
  313. hl4 : tasmlabel;
  314. begin
  315. pass_left_right;
  316. {The location.register will be filled in later (JM)}
  317. location_reset(location,LOC_REGISTER,OS_INT);
  318. {Get a temp register and load the left value into it
  319. and free the location.}
  320. r:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  321. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,left.location,r);
  322. {Allocate EAX.}
  323. cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  324. {Load the right value.}
  325. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,right.location,NR_EAX);
  326. {Also allocate EDX, since it is also modified by a mul (JM).}
  327. cg.getcpuregister(current_asmdata.CurrAsmList,NR_EDX);
  328. emit_reg(A_MUL,S_L,r);
  329. if cs_check_overflow in current_settings.localswitches then
  330. begin
  331. current_asmdata.getjumplabel(hl4);
  332. cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4);
  333. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW');
  334. cg.a_label(current_asmdata.CurrAsmList,hl4);
  335. end;
  336. {Free EAX,EDX}
  337. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EDX);
  338. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  339. {Allocate a new register and store the result in EAX in it.}
  340. location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  341. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EAX,location.register);
  342. location_freetemp(current_asmdata.CurrAsmList,left.location);
  343. location_freetemp(current_asmdata.CurrAsmList,right.location);
  344. end;
  345. begin
  346. caddnode:=ti386addnode;
  347. end.