cgcpu.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  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. begin
  198. Case Op of
  199. OP_DIV, OP_IDIV:
  200. Begin
  201. if ispowerof2(longint(a),power) then
  202. begin
  203. case op of
  204. OP_DIV:
  205. opcode := A_SHR;
  206. OP_IDIV:
  207. opcode := A_SAR;
  208. end;
  209. list.concat(taicpu.op_const_reg(opcode,regsize(reg),power,
  210. reg));
  211. exit;
  212. end;
  213. { the rest should be handled specifically in the code }
  214. { generator because of the silly register usage restraints }
  215. internalerror(200109224);
  216. End;
  217. OP_MUL,OP_IMUL:
  218. begin
  219. if not(cs_check_overflow in aktlocalswitches) and
  220. ispowerof2(longint(a),power) then
  221. begin
  222. list.concat(taicpu.op_const_reg(A_SHL,regsize(reg),power,
  223. reg));
  224. exit;
  225. end;
  226. if op = OP_IMUL then
  227. list.concat(taicpu.op_const_reg(A_IMUL,regsize(reg),
  228. longint(a),reg))
  229. else
  230. { OP_MUL should be handled specifically in the code }
  231. { generator because of the silly register usage restraints }
  232. internalerror(200109225);
  233. end;
  234. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  235. if (a = 1) and
  236. (op in [OP_ADD,OP_SUB]) then
  237. if op = OP_ADD then
  238. list.concat(taicpu.op_reg(A_INC,regsize(reg),reg))
  239. else
  240. list.concat(taicpu.op_reg(A_DEC,regsize(reg),reg))
  241. else if (a = 0) then
  242. if (op <> OP_AND) then
  243. exit
  244. else
  245. list.concat(taicpu.op_const_reg(A_MOV,regsize(reg),0,reg))
  246. else
  247. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],regsize(reg),
  248. longint(a),reg));
  249. OP_SHL,OP_SHR,OP_SAR:
  250. begin
  251. if (a and 31) <> 0 Then
  252. list.concat(taicpu.op_const_reg(
  253. TOpCG2AsmOp[op],regsize(reg),a and 31,reg));
  254. if (a shr 5) <> 0 Then
  255. internalerror(68991);
  256. end
  257. else internalerror(68992);
  258. end;
  259. end;
  260. procedure tcg386.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  261. var
  262. opcode: tasmop;
  263. power: longint;
  264. begin
  265. Case Op of
  266. OP_DIV, OP_IDIV:
  267. Begin
  268. if ispowerof2(longint(a),power) then
  269. begin
  270. case op of
  271. OP_DIV:
  272. opcode := A_SHR;
  273. OP_IDIV:
  274. opcode := A_SAR;
  275. end;
  276. list.concat(taicpu.op_const_ref(opcode,
  277. TCgSize2OpSize[size],power,newreference(ref)));
  278. exit;
  279. end;
  280. { the rest should be handled specifically in the code }
  281. { generator because of the silly register usage restraints }
  282. internalerror(200109231);
  283. End;
  284. OP_MUL,OP_IMUL:
  285. begin
  286. if not(cs_check_overflow in aktlocalswitches) and
  287. ispowerof2(longint(a),power) then
  288. begin
  289. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  290. power,newreference(ref)));
  291. exit;
  292. end;
  293. { can't multiply a memory location directly with a constant }
  294. if op = OP_IMUL then
  295. inherited a_op_const_ref(list,op,size,a,ref)
  296. else
  297. { OP_MUL should be handled specifically in the code }
  298. { generator because of the silly register usage restraints }
  299. internalerror(200109232);
  300. end;
  301. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  302. if (a = 1) and
  303. (op in [OP_ADD,OP_SUB]) then
  304. if op = OP_ADD then
  305. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],
  306. newreference(ref)))
  307. else
  308. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],
  309. newreference(ref)))
  310. else if (a = 0) then
  311. if (op <> OP_AND) then
  312. exit
  313. else
  314. a_load_const_ref(list,size,0,ref)
  315. else
  316. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  317. TCgSize2OpSize[size],longint(a),newreference(ref)));
  318. OP_SHL,OP_SHR,OP_SAR:
  319. begin
  320. if (a and 31) <> 0 Then
  321. list.concat(taicpu.op_const_ref(
  322. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,newreference(ref)));
  323. if (a shr 5) <> 0 Then
  324. internalerror(68991);
  325. end
  326. else internalerror(68992);
  327. end;
  328. end;
  329. procedure tcg386.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  330. var
  331. regloadsize: tcgsize;
  332. dstsize: topsize;
  333. tmpreg : tregister;
  334. popecx : boolean;
  335. begin
  336. dstsize := makeregsize(dst,size);
  337. case op of
  338. OP_NEG,OP_NOT:
  339. begin
  340. if src <> R_NO then
  341. internalerror(200112291);
  342. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  343. end;
  344. OP_MUL,OP_DIV,OP_IDIV:
  345. { special stuff, needs separate handling inside code }
  346. { generator }
  347. internalerror(200109233);
  348. OP_SHR,OP_SHL,OP_SAR:
  349. begin
  350. tmpreg := R_NO;
  351. { we need cl to hold the shift count, so if the destination }
  352. { is ecx, save it to a temp for now }
  353. if dst in [R_ECX,R_CX,R_CL] then
  354. begin
  355. case regsize(dst) of
  356. S_B: regloadsize := OS_8;
  357. S_W: regloadsize := OS_16;
  358. else regloadsize := OS_32;
  359. end;
  360. tmpreg := get_scratch_reg(list);
  361. a_load_reg_reg(list,regloadsize,src,tmpreg);
  362. end;
  363. if not(src in [R_ECX,R_CX,R_CL]) then
  364. begin
  365. { is ecx still free (it's also free if it was allocated }
  366. { to dst, since we've moved dst somewhere else already) }
  367. if not((dst = R_ECX) or
  368. ((R_ECX in unused) and
  369. { this will always be true, it's just here to }
  370. { allocate ecx }
  371. (getexplicitregister32(R_ECX) = R_ECX))) then
  372. begin
  373. list.concat(taicpu.op_reg(A_PUSH,S_L,R_ECX));
  374. popecx := true;
  375. end;
  376. a_load_reg_reg(list,OS_8,makereg8(src),R_CL);
  377. end
  378. else
  379. src := R_CL;
  380. { do the shift }
  381. if tmpreg = R_NO then
  382. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  383. R_CL,dst))
  384. else
  385. begin
  386. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_L,
  387. R_CL,tmpreg));
  388. { move result back to the destination }
  389. a_load_reg_reg(list,OS_32,tmpreg,R_ECX);
  390. free_scratch_reg(list,tmpreg);
  391. end;
  392. if popecx then
  393. list.concat(taicpu.op_reg(A_POP,S_L,R_ECX))
  394. else if not (dst in [R_ECX,R_CX,R_CL]) then
  395. ungetregister32(R_ECX);
  396. end;
  397. else
  398. begin
  399. if regsize(src) <> dstsize then
  400. internalerror(200109226);
  401. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  402. src,dst));
  403. end;
  404. end;
  405. end;
  406. procedure tcg386.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  407. var
  408. opsize: topsize;
  409. begin
  410. if ref.is_immediate then
  411. a_op_const_reg(list,op,aword(ref.offset),reg)
  412. else
  413. begin
  414. case op of
  415. OP_NEG,OP_NOT,OP_IMUL:
  416. begin
  417. inherited a_op_ref_reg(list,op,size,ref,reg);
  418. end;
  419. OP_MUL,OP_DIV,OP_IDIV:
  420. { special stuff, needs separate handling inside code }
  421. { generator }
  422. internalerror(200109239);
  423. else
  424. begin
  425. opsize := makeregsize(reg,size);
  426. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],opsize,
  427. newreference(ref),reg));
  428. end;
  429. end;
  430. end;
  431. end;
  432. procedure tcg386.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  433. var
  434. opsize: topsize;
  435. begin
  436. case op of
  437. OP_NEG,OP_NOT:
  438. begin
  439. if reg <> R_NO then
  440. internalerror(200109237);
  441. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],
  442. newreference(ref)));
  443. end;
  444. OP_IMUL:
  445. begin
  446. { this one needs a load/imul/store, which is the default }
  447. inherited a_op_ref_reg(list,op,size,ref,reg);
  448. end;
  449. OP_MUL,OP_DIV,OP_IDIV:
  450. { special stuff, needs separate handling inside code }
  451. { generator }
  452. internalerror(200109238);
  453. else
  454. begin
  455. opsize := tcgsize2opsize[size];
  456. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,
  457. newreference(ref)));
  458. end;
  459. end;
  460. end;
  461. procedure tcg386.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  462. size: tcgsize; a: aword; src, dst: tregister);
  463. var
  464. tmpref: treference;
  465. power: longint;
  466. opsize: topsize;
  467. begin
  468. opsize := regsize(src);
  469. if (opsize <> S_L) or
  470. not (size in [OS_32,OS_S32]) then
  471. begin
  472. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  473. exit;
  474. end;
  475. { if we get here, we have to do a 32 bit calculation, guaranteed }
  476. Case Op of
  477. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  478. OP_SAR:
  479. { can't do anything special for these }
  480. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  481. OP_IMUL:
  482. begin
  483. if not(cs_check_overflow in aktlocalswitches) and
  484. ispowerof2(longint(a),power) then
  485. { can be done with a shift }
  486. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  487. list.concat(taicpu.op_const_reg_reg(A_IMUL,S_L,longint(a),src,dst));
  488. end;
  489. OP_ADD, OP_SUB:
  490. if (a = 0) then
  491. a_load_reg_reg(list,size,src,dst)
  492. else
  493. begin
  494. reset_reference(tmpref);
  495. tmpref.base := src;
  496. tmpref.offset := longint(a);
  497. if op = OP_SUB then
  498. tmpref.offset := -tmpref.offset;
  499. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(tmpref),
  500. dst));
  501. end
  502. else internalerror(200112302);
  503. end;
  504. end;
  505. procedure tcg386.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  506. size: tcgsize; src1, src2, dst: tregister);
  507. var
  508. tmpref: treference;
  509. opsize: topsize;
  510. begin
  511. opsize := regsize(src1);
  512. if (opsize <> S_L) or
  513. (regsize(src2) <> S_L) or
  514. not (size in [OS_32,OS_S32]) then
  515. begin
  516. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  517. exit;
  518. end;
  519. { if we get here, we have to do a 32 bit calculation, guaranteed }
  520. Case Op of
  521. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  522. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  523. { can't do anything special for these }
  524. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  525. OP_IMUL:
  526. list.concat(taicpu.op_reg_reg_reg(A_IMUL,S_L,src1,src2,dst));
  527. OP_ADD:
  528. begin
  529. reset_reference(tmpref);
  530. tmpref.base := src1;
  531. tmpref.index := src2;
  532. tmpref.scalefactor := 1;
  533. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(tmpref),
  534. dst));
  535. end
  536. else internalerror(200112303);
  537. end;
  538. end;
  539. {*************** compare instructructions ****************}
  540. procedure tcg386.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  541. l : tasmlabel);
  542. begin
  543. if a <> 0 then
  544. list.concat(taicpu.op_const_reg(A_CMP,regsize(reg),longint(a),
  545. reg))
  546. else
  547. list.concat(taicpu.op_reg_reg(A_TEST,regsize(reg),reg,reg));
  548. a_jmp_cond(list,cmp_op,l);
  549. end;
  550. procedure tcg386.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  551. l : tasmlabel);
  552. begin
  553. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],
  554. longint(a),newreference(ref)));
  555. a_jmp_cond(list,cmp_op,l);
  556. end;
  557. procedure tcg386.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  558. reg1,reg2 : tregister;l : tasmlabel);
  559. begin
  560. if regsize(reg1) <> regsize(reg2) then
  561. internalerror(200109226);
  562. list.concat(taicpu.op_reg_reg(A_CMP,regsize(reg1),reg1,reg2));
  563. a_jmp_cond(list,cmp_op,l);
  564. end;
  565. procedure tcg386.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  566. var
  567. opsize: topsize;
  568. begin
  569. opsize := makeregsize(reg,size);
  570. list.concat(taicpu.op_ref_reg(A_CMP,opsize,newreference(ref),reg));
  571. a_jmp_cond(list,cmp_op,l);
  572. end;
  573. procedure tcg386.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  574. var
  575. ai : taicpu;
  576. begin
  577. if cond=OC_None then
  578. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  579. else
  580. begin
  581. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  582. ai.SetCondition(TOpCmp2AsmCond[cond]);
  583. end;
  584. ai.is_jmp:=true;
  585. list.concat(ai);
  586. end;
  587. procedure tcg386.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  588. var
  589. ai : taicpu;
  590. begin
  591. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  592. ai.SetCondition(flags_to_cond(f));
  593. ai.is_jmp := true;
  594. list.concat(ai);
  595. end;
  596. procedure tcg386.g_flags2reg(list: taasmoutput; const f: tresflags; reg: TRegister);
  597. var
  598. ai : taicpu;
  599. hreg : tregister;
  600. begin
  601. hreg := makereg8(reg);
  602. ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
  603. ai.SetCondition(flags_to_cond(f));
  604. list.concat(ai);
  605. if hreg<>reg then
  606. begin
  607. if reg in regset16bit then
  608. emit_to_reg16(hreg)
  609. else
  610. emit_to_reg32(hreg);
  611. end;
  612. end;
  613. { *********** entry/exit code and address loading ************ }
  614. procedure tcg386.g_stackframe_entry(list : taasmoutput;localsize : longint);
  615. begin
  616. runerror(211);
  617. end;
  618. procedure tcg386.g_restore_frame_pointer(list : taasmoutput);
  619. begin
  620. runerror(211);
  621. end;
  622. procedure tcg386.g_push_exception_value_reg(list : taasmoutput;reg : tregister);
  623. begin
  624. runerror(211);
  625. end;
  626. procedure tcg386.g_push_exception_value_const(list : taasmoutput;reg : tregister);
  627. begin
  628. runerror(211);
  629. end;
  630. procedure tcg386.g_pop_exception_value_reg(list : taasmoutput;reg : tregister);
  631. begin
  632. runerror(211);
  633. end;
  634. procedure tcg386.g_return_from_proc(list : taasmoutput;parasize : aword);
  635. begin
  636. runerror(211);
  637. end;
  638. procedure tcg386.a_loadaddress_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  639. begin
  640. list.concat(taicpu.op_ref_reg(A_LEA,S_L,newreference(ref),r));
  641. end;
  642. function tcg386.makeregsize(var reg: tregister; size: tcgsize): topsize;
  643. begin
  644. { this function only allows downsizing a register, because otherwise }
  645. { we may start working with garbage (JM) }
  646. case size of
  647. OS_32,OS_S32:
  648. begin
  649. if not (reg in [R_EAX..R_EDI]) then
  650. internalerror(2001092313);
  651. result := S_L;
  652. end;
  653. OS_8,OS_S8:
  654. begin
  655. reg := makereg8(reg);
  656. result := S_B;
  657. end;
  658. OS_16,OS_S16:
  659. begin
  660. if reg in [R_AL..R_BH] then
  661. internalerror(2001092314);
  662. reg := makereg16(reg);
  663. result := S_W;
  664. end;
  665. else
  666. internalerror(2001092312);
  667. end;
  668. end;
  669. { ************* concatcopy ************ }
  670. procedure tcg386.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  671. { temp implementation, until it's permanenty moved here from cga.pas }
  672. var
  673. oldlist: taasmoutput;
  674. begin
  675. if list <> exprasmlist then
  676. begin
  677. oldlist := exprasmlist;
  678. exprasmlist := list;
  679. end;
  680. cga.concatcopy(source,dest,len,delsource,loadref);
  681. if list <> exprasmlist then
  682. list := oldlist;
  683. end;
  684. function tcg386.reg_cgsize(const reg: tregister): tcgsize;
  685. const
  686. regsize_2_cgsize: array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  687. begin
  688. result := regsize_2_cgsize[regsize(reg)];
  689. end;
  690. {***************** This is private property, keep out! :) *****************}
  691. procedure tcg386.sizes2load(s1: tcgsize; s2: topsize; var op: tasmop; var s3: topsize);
  692. begin
  693. case s2 of
  694. S_B:
  695. if S1 in [OS_8,OS_S8] then
  696. s3 := S_B
  697. else internalerror(200109221);
  698. S_W:
  699. case s1 of
  700. OS_8,OS_S8:
  701. s3 := S_BW;
  702. OS_16,OS_S16:
  703. s3 := S_W;
  704. else internalerror(200109222);
  705. end;
  706. S_L:
  707. case s1 of
  708. OS_8,OS_S8:
  709. s3 := S_BL;
  710. OS_16,OS_S16:
  711. s3 := S_WL;
  712. OS_32,OS_S32:
  713. s3 := S_L;
  714. else internalerror(200109223);
  715. end;
  716. else internalerror(200109227);
  717. end;
  718. if s3 in [S_B,S_W,S_L] then
  719. op := A_MOV
  720. else if s1 in [OS_8,OS_16,OS_32] then
  721. op := A_MOVZX
  722. else
  723. op := A_MOVSX;
  724. end;
  725. begin
  726. cg := tcg386.create;
  727. end.
  728. {
  729. $Log$
  730. Revision 1.7 2002-03-04 19:10:12 peter
  731. * removed compiler warnings
  732. Revision 1.6 2001/12/30 17:24:46 jonas
  733. * range checking is now processor independent (part in cgobj,
  734. part in cg64f32) and should work correctly again (it needed
  735. some changes after the changes of the low and high of
  736. tordef's to int64)
  737. * maketojumpbool() is now processor independent (in ncgutil)
  738. * getregister32 is now called getregisterint
  739. Revision 1.5 2001/12/29 15:29:59 jonas
  740. * powerpc/cgcpu.pas compiles :)
  741. * several powerpc-related fixes
  742. * cpuasm unit is now based on common tainst unit
  743. + nppcmat unit for powerpc (almost complete)
  744. Revision 1.4 2001/10/04 14:33:28 jonas
  745. * fixed range check errors
  746. Revision 1.3 2001/09/30 16:17:18 jonas
  747. * made most constant and mem handling processor independent
  748. Revision 1.2 2001/09/29 21:32:19 jonas
  749. * fixed bug in a_load_reg_reg + implemented a_call
  750. Revision 1.1 2001/09/28 20:39:33 jonas
  751. * changed all flow control structures (except for exception handling
  752. related things) to processor independent code (in new ncgflw unit)
  753. + generic cgobj unit which contains lots of code generator helpers with
  754. global "cg" class instance variable
  755. + cgcpu unit for i386 (implements processor specific routines of the above
  756. unit)
  757. * updated cgbase and cpubase for the new code generator units
  758. * include ncgflw unit in cpunode unit
  759. }