cgcpu.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This unit implements the code generator for the i386
  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 defines.inc}
  20. interface
  21. uses
  22. cgbase,cgobj,cg64f32,aasm,cpuasm,cpubase,cpuinfo;
  23. type
  24. tcg386 = class(tcg64f32)
  25. { passing parameters, per default the parameter is pushed }
  26. { nr gives the number of the parameter (enumerated from }
  27. { left to right), this allows to move the parameter to }
  28. { register, if the cpu supports register calling }
  29. { conventions }
  30. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;nr : longint);override;
  31. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;nr : longint);override;
  32. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;nr : longint);override;
  33. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;nr : longint);override;
  34. procedure a_call_name(list : taasmoutput;const s : string;
  35. offset : longint);override;
  36. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  37. procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference); override;
  38. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  39. procedure a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  40. procedure a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  41. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  42. size: tcgsize; a: aword; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. { move instructions }
  46. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  47. procedure a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);override;
  48. procedure a_load_reg_ref(list : taasmoutput; size: tcgsize; reg : tregister;const ref : treference);override;
  49. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref : treference;reg : tregister);override;
  50. procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
  51. procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister); override;
  52. { comparison operations }
  53. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  54. l : tasmlabel);override;
  55. procedure a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  56. l : tasmlabel);override;
  57. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  58. procedure a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  59. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel); override;
  60. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  61. procedure g_flags2reg(list: taasmoutput; const f: tresflags; reg: TRegister); override;
  62. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  63. procedure g_restore_frame_pointer(list : taasmoutput);override;
  64. procedure g_push_exception_value_reg(list : taasmoutput;reg : tregister);override;
  65. procedure g_push_exception_value_const(list : taasmoutput;reg : tregister);override;
  66. procedure g_pop_exception_value_reg(list : taasmoutput;reg : tregister);override;
  67. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  68. procedure a_loadaddress_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  69. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  70. function makeregsize(var reg: tregister; size: tcgsize): topsize; override;
  71. class function reg_cgsize(const reg: tregister): tcgsize; override;
  72. private
  73. procedure sizes2load(s1: tcgsize; s2: topsize; var op: tasmop; var s3: topsize);
  74. end;
  75. const
  76. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_ADD,A_AND,A_DIV,
  77. A_IDIV,A_MUL, A_IMUL, A_NEG,A_NOT,A_OR,
  78. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR);
  79. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_E,C_G,
  80. C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  81. TCGSize2OpSize: Array[tcgsize] of topsize = (S_NO,S_B,S_W,S_L,S_L,
  82. S_B,S_W,S_L,S_L);
  83. implementation
  84. uses
  85. globtype,globals,verbose,systems,cutils,cga,tgcpu;
  86. { we implement the following routines because otherwise we can't }
  87. { instantiate the class since it's abstract }
  88. procedure tcg386.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;nr : longint);
  89. begin
  90. runerror(211);
  91. end;
  92. procedure tcg386.a_param_const(list : taasmoutput;size : tcgsize;a : aword;nr : longint);
  93. begin
  94. runerror(211);
  95. end;
  96. procedure tcg386.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;nr : longint);
  97. var
  98. tmpreg: tregister;
  99. begin
  100. case size of
  101. OS_8,OS_S8,OS_16,OS_S16:
  102. begin
  103. tmpreg := get_scratch_reg(list);
  104. a_load_ref_reg(list,size,r,tmpreg);
  105. if target_info.alignment.paraalign = 2 then
  106. list.concat(taicpu.op_reg(A_PUSH,S_W,makereg16(tmpreg)))
  107. else
  108. list.concat(taicpu.op_reg(A_PUSH,S_L,tmpreg));
  109. end;
  110. OS_32,OS_S32:
  111. list.concat(taicpu.op_ref(A_PUSH,S_L,newreference(r)));
  112. else
  113. internalerror(200109301);
  114. end;
  115. end;
  116. procedure tcg386.a_paramaddr_ref(list : taasmoutput;const r : treference;nr : longint);
  117. begin
  118. runerror(211);
  119. end;
  120. procedure tcg386.a_call_name(list : taasmoutput;const s : string;
  121. offset : longint);
  122. begin
  123. list.concat(taicpu.op_sym_ofs(A_CALL,S_NO,newasmsymbol(s),offset));
  124. end;
  125. {********************** load instructions ********************}
  126. procedure tcg386.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  127. begin
  128. { the optimizer will change it to "xor reg,reg" when loading zero, }
  129. { no need to do it here too (JM) }
  130. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[size],
  131. longint(a),reg))
  132. end;
  133. procedure tcg386.a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);
  134. begin
  135. { zero is often used several times in succession -> load it in a }
  136. { register and then store it to memory, so the optimizer can then }
  137. { remove the unnecessary loads of registers and you get smaller }
  138. { (and faster) code }
  139. if (a = 0) and
  140. (size in [OS_32,OS_S32]) then
  141. inherited a_load_const_ref(list,size,a,ref)
  142. else
  143. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[size],
  144. longint(a),newreference(ref)));
  145. end;
  146. procedure tcg386.a_load_reg_ref(list : taasmoutput; size: TCGSize; reg : tregister;const ref : treference);
  147. begin
  148. list.concat(taicpu.op_reg_ref(A_MOV,TCGSize2OpSize[size],reg,
  149. newreference(ref)));
  150. End;
  151. procedure tcg386.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref: treference;reg : tregister);
  152. var
  153. op: tasmop;
  154. s: topsize;
  155. begin
  156. if ref.is_immediate then
  157. a_load_const_reg(list,size,aword(ref.offset),reg)
  158. else
  159. begin
  160. sizes2load(size,regsize(reg),op,s);
  161. list.concat(taicpu.op_ref_reg(op,s,newreference(ref),reg));
  162. end;
  163. end;
  164. procedure tcg386.a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);
  165. var
  166. op: tasmop;
  167. s: topsize;
  168. begin
  169. sizes2load(size,regsize(reg2),op,s);
  170. if (makereg32(reg1) = makereg32(reg2)) then
  171. { "mov reg1, reg1" doesn't make sense }
  172. if op = A_MOV then
  173. exit
  174. else if (op = A_MOVZX) then
  175. case size of
  176. OS_8:
  177. begin
  178. list.concat(taicpu.op_const_reg(A_AND,regsize(reg2),255,reg2));
  179. exit;
  180. end;
  181. OS_16:
  182. begin
  183. list.concat(taicpu.op_const_reg(A_AND,S_L,65535,reg1));
  184. exit;
  185. end;
  186. end;
  187. list.concat(taicpu.op_reg_reg(op,s,reg1,reg2));
  188. end;
  189. procedure tcg386.a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);
  190. begin
  191. list.concat(taicpu.op_sym_ofs_reg(A_MOV,S_L,sym,ofs,reg));
  192. end;
  193. procedure tcg386.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  194. var
  195. opcode: tasmop;
  196. power: longint;
  197. scratch_register: TRegister;
  198. begin
  199. Case Op of
  200. OP_DIV, OP_IDIV:
  201. Begin
  202. if ispowerof2(longint(a),power) then
  203. begin
  204. case op of
  205. OP_DIV:
  206. opcode := A_SHR;
  207. OP_IDIV:
  208. opcode := A_SAR;
  209. end;
  210. list.concat(taicpu.op_const_reg(opcode,regsize(reg),power,
  211. reg));
  212. exit;
  213. end;
  214. { the rest should be handled specifically in the code }
  215. { generator because of the silly register usage restraints }
  216. internalerror(200109224);
  217. End;
  218. OP_MUL,OP_IMUL:
  219. begin
  220. if not(cs_check_overflow in aktlocalswitches) and
  221. ispowerof2(longint(a),power) then
  222. begin
  223. list.concat(taicpu.op_const_reg(A_SHL,regsize(reg),power,
  224. reg));
  225. exit;
  226. end;
  227. if op = OP_IMUL then
  228. list.concat(taicpu.op_const_reg(A_IMUL,regsize(reg),
  229. longint(a),reg))
  230. else
  231. { OP_MUL should be handled specifically in the code }
  232. { generator because of the silly register usage restraints }
  233. internalerror(200109225);
  234. end;
  235. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  236. if (a = 1) and
  237. (op in [OP_ADD,OP_SUB]) then
  238. if op = OP_ADD then
  239. list.concat(taicpu.op_reg(A_INC,regsize(reg),reg))
  240. else
  241. list.concat(taicpu.op_reg(A_DEC,regsize(reg),reg))
  242. else if (a = 0) then
  243. if (op <> OP_AND) then
  244. exit
  245. else
  246. list.concat(taicpu.op_const_reg(A_MOV,regsize(reg),0,reg))
  247. else
  248. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],regsize(reg),
  249. longint(a),reg));
  250. OP_SHL,OP_SHR,OP_SAR:
  251. begin
  252. if (a and 31) <> 0 Then
  253. list.concat(taicpu.op_const_reg(
  254. TOpCG2AsmOp[op],regsize(reg),a and 31,reg));
  255. if (a shr 5) <> 0 Then
  256. internalerror(68991);
  257. end
  258. else internalerror(68992);
  259. end;
  260. end;
  261. procedure tcg386.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  262. var
  263. opcode: tasmop;
  264. power: longint;
  265. scratch_register: TRegister;
  266. begin
  267. Case Op of
  268. OP_DIV, OP_IDIV:
  269. Begin
  270. if ispowerof2(longint(a),power) then
  271. begin
  272. case op of
  273. OP_DIV:
  274. opcode := A_SHR;
  275. OP_IDIV:
  276. opcode := A_SAR;
  277. end;
  278. list.concat(taicpu.op_const_ref(opcode,
  279. TCgSize2OpSize[size],power,newreference(ref)));
  280. exit;
  281. end;
  282. { the rest should be handled specifically in the code }
  283. { generator because of the silly register usage restraints }
  284. internalerror(200109231);
  285. End;
  286. OP_MUL,OP_IMUL:
  287. begin
  288. if not(cs_check_overflow in aktlocalswitches) and
  289. ispowerof2(longint(a),power) then
  290. begin
  291. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  292. power,newreference(ref)));
  293. exit;
  294. end;
  295. { can't multiply a memory location directly with a constant }
  296. if op = OP_IMUL then
  297. inherited a_op_const_ref(list,op,size,a,ref)
  298. else
  299. { OP_MUL should be handled specifically in the code }
  300. { generator because of the silly register usage restraints }
  301. internalerror(200109232);
  302. end;
  303. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  304. if (a = 1) and
  305. (op in [OP_ADD,OP_SUB]) then
  306. if op = OP_ADD then
  307. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],
  308. newreference(ref)))
  309. else
  310. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],
  311. newreference(ref)))
  312. else if (a = 0) then
  313. if (op <> OP_AND) then
  314. exit
  315. else
  316. a_load_const_ref(list,size,0,ref)
  317. else
  318. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  319. TCgSize2OpSize[size],longint(a),newreference(ref)));
  320. OP_SHL,OP_SHR,OP_SAR:
  321. begin
  322. if (a and 31) <> 0 Then
  323. list.concat(taicpu.op_const_ref(
  324. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,newreference(ref)));
  325. if (a shr 5) <> 0 Then
  326. internalerror(68991);
  327. end
  328. else internalerror(68992);
  329. end;
  330. end;
  331. procedure tcg386.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  332. var
  333. regloadsize: tcgsize;
  334. dstsize: topsize;
  335. tmpreg : tregister;
  336. popecx : boolean;
  337. begin
  338. dstsize := makeregsize(dst,size);
  339. case op of
  340. OP_NEG,OP_NOT:
  341. begin
  342. if src <> R_NO then
  343. internalerror(200112291);
  344. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  345. end;
  346. OP_MUL,OP_DIV,OP_IDIV:
  347. { special stuff, needs separate handling inside code }
  348. { generator }
  349. internalerror(200109233);
  350. OP_SHR,OP_SHL,OP_SAR:
  351. begin
  352. tmpreg := R_NO;
  353. { we need cl to hold the shift count, so if the destination }
  354. { is ecx, save it to a temp for now }
  355. if dst in [R_ECX,R_CX,R_CL] then
  356. begin
  357. case regsize(dst) of
  358. S_B: regloadsize := OS_8;
  359. S_W: regloadsize := OS_16;
  360. else regloadsize := OS_32;
  361. end;
  362. tmpreg := get_scratch_reg(list);
  363. a_load_reg_reg(list,regloadsize,src,tmpreg);
  364. end;
  365. if not(src in [R_ECX,R_CX,R_CL]) then
  366. begin
  367. { is ecx still free (it's also free if it was allocated }
  368. { to dst, since we've moved dst somewhere else already) }
  369. if not((dst = R_ECX) or
  370. ((R_ECX in unused) and
  371. { this will always be true, it's just here to }
  372. { allocate ecx }
  373. (getexplicitregister32(R_ECX) = R_ECX))) then
  374. begin
  375. list.concat(taicpu.op_reg(A_PUSH,S_L,R_ECX));
  376. popecx := true;
  377. end;
  378. a_load_reg_reg(list,OS_8,makereg8(src),R_CL);
  379. end
  380. else
  381. src := R_CL;
  382. { do the shift }
  383. if tmpreg = R_NO then
  384. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  385. R_CL,dst))
  386. else
  387. begin
  388. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_L,
  389. R_CL,tmpreg));
  390. { move result back to the destination }
  391. a_load_reg_reg(list,OS_32,tmpreg,R_ECX);
  392. free_scratch_reg(list,tmpreg);
  393. end;
  394. if popecx then
  395. list.concat(taicpu.op_reg(A_POP,S_L,R_ECX))
  396. else if not (dst in [R_ECX,R_CX,R_CL]) then
  397. ungetregister32(R_ECX);
  398. end;
  399. else
  400. begin
  401. if regsize(src) <> dstsize then
  402. internalerror(200109226);
  403. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  404. src,dst));
  405. end;
  406. end;
  407. end;
  408. procedure tcg386.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  409. var
  410. opsize: topsize;
  411. begin
  412. if ref.is_immediate then
  413. a_op_const_reg(list,op,aword(ref.offset),reg)
  414. else
  415. begin
  416. case op of
  417. OP_NEG,OP_NOT,OP_IMUL:
  418. begin
  419. inherited a_op_ref_reg(list,op,size,ref,reg);
  420. end;
  421. OP_MUL,OP_DIV,OP_IDIV:
  422. { special stuff, needs separate handling inside code }
  423. { generator }
  424. internalerror(200109239);
  425. else
  426. begin
  427. opsize := makeregsize(reg,size);
  428. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],opsize,
  429. newreference(ref),reg));
  430. end;
  431. end;
  432. end;
  433. end;
  434. procedure tcg386.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  435. var
  436. opsize: topsize;
  437. begin
  438. case op of
  439. OP_NEG,OP_NOT:
  440. begin
  441. if reg <> R_NO then
  442. internalerror(200109237);
  443. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],
  444. newreference(ref)));
  445. end;
  446. OP_IMUL:
  447. begin
  448. { this one needs a load/imul/store, which is the default }
  449. inherited a_op_ref_reg(list,op,size,ref,reg);
  450. end;
  451. OP_MUL,OP_DIV,OP_IDIV:
  452. { special stuff, needs separate handling inside code }
  453. { generator }
  454. internalerror(200109238);
  455. else
  456. begin
  457. opsize := tcgsize2opsize[size];
  458. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,
  459. newreference(ref)));
  460. end;
  461. end;
  462. end;
  463. procedure tcg386.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  464. size: tcgsize; a: aword; src, dst: tregister);
  465. var
  466. tmpref: treference;
  467. power: longint;
  468. opsize: topsize;
  469. begin
  470. opsize := regsize(src);
  471. if (opsize <> S_L) or
  472. not (size in [OS_32,OS_S32]) then
  473. begin
  474. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  475. exit;
  476. end;
  477. { if we get here, we have to do a 32 bit calculation, guaranteed }
  478. Case Op of
  479. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  480. OP_SAR:
  481. { can't do anything special for these }
  482. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  483. OP_IMUL:
  484. begin
  485. if not(cs_check_overflow in aktlocalswitches) and
  486. ispowerof2(longint(a),power) then
  487. { can be done with a shift }
  488. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  489. list.concat(taicpu.op_const_reg_reg(A_IMUL,S_L,longint(a),src,dst));
  490. end;
  491. OP_ADD, OP_SUB:
  492. if (a = 0) then
  493. a_load_reg_reg(list,size,src,dst)
  494. else
  495. begin
  496. reset_reference(tmpref);
  497. tmpref.base := src;
  498. tmpref.offset := longint(a);
  499. if op = OP_SUB then
  500. tmpref.offset := -tmpref.offset;
  501. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(tmpref),
  502. dst));
  503. end
  504. else internalerror(200112302);
  505. end;
  506. end;
  507. procedure tcg386.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  508. size: tcgsize; src1, src2, dst: tregister);
  509. var
  510. tmpref: treference;
  511. power: longint;
  512. opsize: topsize;
  513. begin
  514. opsize := regsize(src1);
  515. if (opsize <> S_L) or
  516. (regsize(src2) <> S_L) or
  517. not (size in [OS_32,OS_S32]) then
  518. begin
  519. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  520. exit;
  521. end;
  522. { if we get here, we have to do a 32 bit calculation, guaranteed }
  523. Case Op of
  524. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  525. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  526. { can't do anything special for these }
  527. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  528. OP_IMUL:
  529. list.concat(taicpu.op_reg_reg_reg(A_IMUL,S_L,src1,src2,dst));
  530. OP_ADD:
  531. begin
  532. reset_reference(tmpref);
  533. tmpref.base := src1;
  534. tmpref.index := src2;
  535. tmpref.scalefactor := 1;
  536. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(tmpref),
  537. dst));
  538. end
  539. else internalerror(200112303);
  540. end;
  541. end;
  542. {*************** compare instructructions ****************}
  543. procedure tcg386.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  544. l : tasmlabel);
  545. begin
  546. if a <> 0 then
  547. list.concat(taicpu.op_const_reg(A_CMP,regsize(reg),longint(a),
  548. reg))
  549. else
  550. list.concat(taicpu.op_reg_reg(A_TEST,regsize(reg),reg,reg));
  551. a_jmp_cond(list,cmp_op,l);
  552. end;
  553. procedure tcg386.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  554. l : tasmlabel);
  555. begin
  556. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],
  557. longint(a),newreference(ref)));
  558. a_jmp_cond(list,cmp_op,l);
  559. end;
  560. procedure tcg386.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  561. reg1,reg2 : tregister;l : tasmlabel);
  562. begin
  563. if regsize(reg1) <> regsize(reg2) then
  564. internalerror(200109226);
  565. list.concat(taicpu.op_reg_reg(A_CMP,regsize(reg1),reg1,reg2));
  566. a_jmp_cond(list,cmp_op,l);
  567. end;
  568. procedure tcg386.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  569. var
  570. opsize: topsize;
  571. begin
  572. opsize := makeregsize(reg,size);
  573. list.concat(taicpu.op_ref_reg(A_CMP,opsize,newreference(ref),reg));
  574. a_jmp_cond(list,cmp_op,l);
  575. end;
  576. procedure tcg386.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  577. var
  578. ai : taicpu;
  579. begin
  580. if cond=OC_None then
  581. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  582. else
  583. begin
  584. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  585. ai.SetCondition(TOpCmp2AsmCond[cond]);
  586. end;
  587. ai.is_jmp:=true;
  588. list.concat(ai);
  589. end;
  590. procedure tcg386.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  591. var
  592. ai : taicpu;
  593. begin
  594. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  595. ai.SetCondition(flags_to_cond(f));
  596. ai.is_jmp := true;
  597. list.concat(ai);
  598. end;
  599. procedure tcg386.g_flags2reg(list: taasmoutput; const f: tresflags; reg: TRegister);
  600. var
  601. ai : taicpu;
  602. hreg : tregister;
  603. begin
  604. hreg := makereg8(reg);
  605. ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
  606. ai.SetCondition(flags_to_cond(f));
  607. list.concat(ai);
  608. if hreg<>reg then
  609. begin
  610. if reg in regset16bit then
  611. emit_to_reg16(hreg)
  612. else
  613. emit_to_reg32(hreg);
  614. end;
  615. end;
  616. { *********** entry/exit code and address loading ************ }
  617. procedure tcg386.g_stackframe_entry(list : taasmoutput;localsize : longint);
  618. begin
  619. runerror(211);
  620. end;
  621. procedure tcg386.g_restore_frame_pointer(list : taasmoutput);
  622. begin
  623. runerror(211);
  624. end;
  625. procedure tcg386.g_push_exception_value_reg(list : taasmoutput;reg : tregister);
  626. begin
  627. runerror(211);
  628. end;
  629. procedure tcg386.g_push_exception_value_const(list : taasmoutput;reg : tregister);
  630. begin
  631. runerror(211);
  632. end;
  633. procedure tcg386.g_pop_exception_value_reg(list : taasmoutput;reg : tregister);
  634. begin
  635. runerror(211);
  636. end;
  637. procedure tcg386.g_return_from_proc(list : taasmoutput;parasize : aword);
  638. begin
  639. runerror(211);
  640. end;
  641. procedure tcg386.a_loadaddress_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  642. begin
  643. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(ref),r));
  644. end;
  645. function tcg386.makeregsize(var reg: tregister; size: tcgsize): topsize;
  646. begin
  647. { this function only allows downsizing a register, because otherwise }
  648. { we may start working with garbage (JM) }
  649. case size of
  650. OS_32,OS_S32:
  651. begin
  652. if not (reg in [R_EAX..R_EDI]) then
  653. internalerror(2001092313);
  654. result := S_L;
  655. end;
  656. OS_8,OS_S8:
  657. begin
  658. reg := makereg8(reg);
  659. result := S_B;
  660. end;
  661. OS_16,OS_S16:
  662. begin
  663. if reg in [R_AL..R_BH] then
  664. internalerror(2001092314);
  665. reg := makereg16(reg);
  666. result := S_W;
  667. end;
  668. else
  669. internalerror(2001092312);
  670. end;
  671. end;
  672. { ************* concatcopy ************ }
  673. procedure tcg386.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  674. { temp implementation, until it's permanenty moved here from cga.pas }
  675. var
  676. oldlist: taasmoutput;
  677. begin
  678. if list <> exprasmlist then
  679. begin
  680. oldlist := exprasmlist;
  681. exprasmlist := list;
  682. end;
  683. cga.concatcopy(source,dest,len,delsource,loadref);
  684. if list <> exprasmlist then
  685. list := oldlist;
  686. end;
  687. function tcg386.reg_cgsize(const reg: tregister): tcgsize;
  688. const
  689. regsize_2_cgsize: array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  690. begin
  691. result := regsize_2_cgsize[regsize(reg)];
  692. end;
  693. {***************** This is private property, keep out! :) *****************}
  694. procedure tcg386.sizes2load(s1: tcgsize; s2: topsize; var op: tasmop; var s3: topsize);
  695. begin
  696. case s2 of
  697. S_B:
  698. if S1 in [OS_8,OS_S8] then
  699. s3 := S_B
  700. else internalerror(200109221);
  701. S_W:
  702. case s1 of
  703. OS_8,OS_S8:
  704. s3 := S_BW;
  705. OS_16,OS_S16:
  706. s3 := S_W;
  707. else internalerror(200109222);
  708. end;
  709. S_L:
  710. case s1 of
  711. OS_8,OS_S8:
  712. s3 := S_BL;
  713. OS_16,OS_S16:
  714. s3 := S_WL;
  715. OS_32,OS_S32:
  716. s3 := S_L;
  717. else internalerror(200109223);
  718. end;
  719. else internalerror(200109227);
  720. end;
  721. if s3 in [S_B,S_W,S_L] then
  722. op := A_MOV
  723. else if s1 in [OS_8,OS_16,OS_32] then
  724. op := A_MOVZX
  725. else
  726. op := A_MOVSX;
  727. end;
  728. begin
  729. cg := tcg386.create;
  730. end.
  731. {
  732. $Log$
  733. Revision 1.6 2001-12-30 17:24:46 jonas
  734. * range checking is now processor independent (part in cgobj, part in cg64f32) and should work correctly again (it needed some changes after the changes of the low and high of tordef's to int64) * maketojumpbool() is now processor independent (in ncgutil) * getregister32 is now called getregisterint
  735. Revision 1.5 2001/12/29 15:29:59 jonas
  736. * powerpc/cgcpu.pas compiles :)
  737. * several powerpc-related fixes
  738. * cpuasm unit is now based on common tainst unit
  739. + nppcmat unit for powerpc (almost complete)
  740. Revision 1.4 2001/10/04 14:33:28 jonas
  741. * fixed range check errors
  742. Revision 1.3 2001/09/30 16:17:18 jonas
  743. * made most constant and mem handling processor independent
  744. Revision 1.2 2001/09/29 21:32:19 jonas
  745. * fixed bug in a_load_reg_reg + implemented a_call
  746. Revision 1.1 2001/09/28 20:39:33 jonas
  747. * changed all flow control structures (except for exception handling
  748. related things) to processor independent code (in new ncgflw unit)
  749. + generic cgobj unit which contains lots of code generator helpers with
  750. global "cg" class instance variable
  751. + cgcpu unit for i386 (implements processor specific routines of the above
  752. unit)
  753. * updated cgbase and cpubase for the new code generator units
  754. * include ncgflw unit in cpunode unit
  755. }