cpubase.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
  4. Contains the base types 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. {# Base unit for processor information. This unit contains
  19. enumerations of registers, opcodes, sizes, and other
  20. such things which are processor specific.
  21. }
  22. unit cpubase;
  23. {$i fpcdefs.inc}
  24. interface
  25. uses
  26. cutils,cclasses,
  27. globtype,globals,
  28. cpuinfo,
  29. aasmbase,
  30. cgbase
  31. {$ifdef delphi}
  32. ,dmisc
  33. {$endif}
  34. ;
  35. {*****************************************************************************
  36. Assembler Opcodes
  37. *****************************************************************************}
  38. type
  39. TAsmOp=(A_None,A_ADC,A_ADD,A_AND,A_N,A_BIC,A_BKPT,A_B,A_BL,A_BLX,A_BX,
  40. A_CDP,A_CDP2,A_CLZ,A_CMN,A_CMP,A_EOR,A_LDC,_A_LDC2,
  41. A_LDM,A_LDR,A_LDRB,A_LDRD,A_LDRBT,A_LDRH,A_LDRSB,
  42. A_LDRSH,A_LDRT,A_MCR,A_MCR2,A_MCRR,A_MLA,A_MOV,
  43. A_MRC,A_MRC2,A_MRRC,A_RS,A_MSR,A_MUL,A_MVN,
  44. A_ORR,A_PLD,A_QADD,A_QDADD,A_QDSUB,A_QSUB,A_RSB,A_RSC,
  45. A_SBC,A_SMLAL,A_SMULL,A_SMUL,
  46. A_SMULW,A_STC,A_STC2,A_STM,A_STR,A_STRB,A_STRBT,A_STRD,
  47. A_STRH,A_STRT,A_SUB,A_SWI,A_SWP,A_SWPB,A_TEQ,A_TST,
  48. A_UMLAL,A_UMULL,
  49. { FPA coprocessor instructions }
  50. A_LDF,A_STF,A_LFM,A_SFM,A_FLT,A_FIX,A_WFS,A_RFS,A_RFC,
  51. A_ADF,A_DVF,A_FDV,A_FML,A_FRD,A_MUF,A_POL,A_PW,A_RDF,
  52. A_RMF,A_RPW,A_RSF,A_SUF,A_ABS,A_ACS,A_ASN,A_ATN,A_COS,
  53. A_EXP,A_LOG,A_LGN,A_MVF,A_MNF,A_NRM,A_RND,A_SIN,A_SQT,A_TAN,A_URD,
  54. A_CMF,A_CMFE,A_CNF
  55. { VPA coprocessor codes }
  56. );
  57. { This should define the array of instructions as string }
  58. op2strtable=array[tasmop] of string[11];
  59. const
  60. { First value of opcode enumeration }
  61. firstop = low(tasmop);
  62. { Last value of opcode enumeration }
  63. lastop = high(tasmop);
  64. {*****************************************************************************
  65. Registers
  66. *****************************************************************************}
  67. type
  68. { Number of registers used for indexing in tables }
  69. tregisterindex=0..{$i rarmnor.inc}-1;
  70. const
  71. { Available Superregisters }
  72. {$i rarmsup.inc}
  73. RS_PC = RS_R15;
  74. { No Subregisters }
  75. R_SUBWHOLE = R_SUBNONE;
  76. { Available Registers }
  77. {$i rarmcon.inc}
  78. { aliases }
  79. NR_PC = NR_R15;
  80. { Integer Super registers first and last }
  81. first_int_supreg = RS_R0;
  82. first_int_imreg = $10;
  83. { Float Super register first and last }
  84. first_fpu_supreg = RS_F0;
  85. first_fpu_imreg = $08;
  86. { MM Super register first and last }
  87. first_mm_supreg = RS_S0;
  88. first_mm_imreg = $20;
  89. {$warning TODO Calculate bsstart}
  90. regnumber_count_bsstart = 64;
  91. regnumber_table : array[tregisterindex] of tregister = (
  92. {$i rarmnum.inc}
  93. );
  94. regstabs_table : array[tregisterindex] of shortint = (
  95. {$i rarmsta.inc}
  96. );
  97. regdwarf_table : array[tregisterindex] of shortint = (
  98. {$i rarmdwa.inc}
  99. );
  100. { registers which may be destroyed by calls }
  101. VOLATILE_INTREGISTERS = [RS_R0..RS_R3,RS_R12..RS_R15];
  102. VOLATILE_FPUREGISTERS = [RS_F0..RS_F3];
  103. type
  104. totherregisterset = set of tregisterindex;
  105. {*****************************************************************************
  106. Instruction post fixes
  107. *****************************************************************************}
  108. type
  109. { ARM instructions load/store and arithmetic instructions
  110. can have several instruction post fixes which are collected
  111. in this enumeration
  112. }
  113. TOpPostfix = (PF_None,
  114. { update condition flags
  115. or floating point single }
  116. PF_S,
  117. { floating point size }
  118. PF_D,PF_E,PF_P,PF_EP,
  119. { load/store }
  120. PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T,
  121. { multiple load/store address modes }
  122. PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA
  123. );
  124. TRoundingMode = (RM_None,RM_P,RM_M,RM_Z);
  125. const
  126. cgsize2fpuoppostfix : array[OS_NO..OS_F128] of toppostfix = (
  127. PF_E,
  128. PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,
  129. PF_S,PF_D,PF_E,PF_None,PF_None);
  130. oppostfix2str : array[TOpPostfix] of string[2] = ('',
  131. 's',
  132. 'd','e','p','ep',
  133. 'b','sb','bt','h','sh','t',
  134. 'ia','ib','da','db','fd','fa','ed','ea');
  135. roundingmode2str : array[TRoundingMode] of string[1] = ('',
  136. 'p','m','z');
  137. {*****************************************************************************
  138. Conditions
  139. *****************************************************************************}
  140. type
  141. TAsmCond=(C_None,
  142. C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
  143. C_GE,C_LT,C_GT,C_LE,C_AL,C_NV
  144. );
  145. const
  146. cond2str : array[TAsmCond] of string[2]=('',
  147. 'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
  148. 'ge','lt','gt','le','al','nv'
  149. );
  150. uppercond2str : array[TAsmCond] of string[2]=('',
  151. 'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
  152. 'GE','LT','GT','LE','AL','NV'
  153. );
  154. inverse_cond : array[TAsmCond] of TAsmCond=(C_None,
  155. C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
  156. C_LT,C_GE,C_LE,C_GT,C_None,C_None
  157. );
  158. {*****************************************************************************
  159. Flags
  160. *****************************************************************************}
  161. type
  162. TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
  163. F_GE,F_LT,F_GT,F_LE);
  164. {*****************************************************************************
  165. Reference
  166. *****************************************************************************}
  167. type
  168. trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup);
  169. taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
  170. tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
  171. { reference record }
  172. preference = ^treference;
  173. treference = record
  174. symbol : tasmsymbol;
  175. { symbol the symbol of this reference is relative to, nil if none }
  176. relsymbol : tasmsymbol;
  177. offset : longint;
  178. base,
  179. index : tregister;
  180. symboldata : tlinkedlistitem;
  181. { reference type addr or symbol itself }
  182. refaddr : trefaddr;
  183. signindex : shortint;
  184. shiftimm : byte;
  185. options : trefoptions;
  186. addressmode : taddressmode;
  187. shiftmode : tshiftmode;
  188. end;
  189. { reference record }
  190. pparareference = ^tparareference;
  191. tparareference = record
  192. index : tregister;
  193. offset : longint;
  194. end;
  195. {*****************************************************************************
  196. Operands
  197. *****************************************************************************}
  198. tupdatereg = (UR_None,UR_Update);
  199. pshifterop = ^tshifterop;
  200. tshifterop = record
  201. shiftmode : tshiftmode;
  202. rs : tregister;
  203. shiftimm : byte;
  204. end;
  205. {*****************************************************************************
  206. Generic Location
  207. *****************************************************************************}
  208. type
  209. { tparamlocation describes where a parameter for a procedure is stored.
  210. References are given from the caller's point of view. The usual
  211. TLocation isn't used, because contains a lot of unnessary fields.
  212. }
  213. tparalocation = record
  214. size : TCGSize;
  215. loc : TCGLoc;
  216. lochigh : TCGLoc;
  217. alignment : byte;
  218. case TCGLoc of
  219. LOC_REFERENCE : (reference : tparareference);
  220. { segment in reference at the same place as in loc_register }
  221. LOC_MMREGISTER,LOC_CMMREGISTER,
  222. LOC_FPUREGISTER,LOC_CFPUREGISTER,
  223. LOC_REGISTER,LOC_CREGISTER : (
  224. case longint of
  225. 1 : (register,registerhigh : tregister);
  226. { overlay a registerlow }
  227. 2 : (registerlow : tregister);
  228. { overlay a 64 Bit register type }
  229. 3 : (reg64 : tregister64);
  230. 4 : (register64 : tregister64);
  231. );
  232. end;
  233. tlocation = record
  234. loc : TCGLoc;
  235. size : TCGSize;
  236. case TCGLoc of
  237. LOC_FLAGS : (resflags : tresflags);
  238. LOC_CONSTANT : (
  239. case longint of
  240. 1 : (value : AWord);
  241. { can't do this, this layout depends on the host cpu. Use }
  242. { lo(valueqword)/hi(valueqword) instead (JM) }
  243. { 2 : (valuelow, valuehigh:AWord); }
  244. { overlay a complete 64 Bit value }
  245. 3 : (value64 : qword);
  246. );
  247. LOC_CREFERENCE,
  248. LOC_REFERENCE : (reference : treference);
  249. { segment in reference at the same place as in loc_register }
  250. LOC_REGISTER,LOC_CREGISTER : (
  251. case longint of
  252. 1 : (register,registerhigh,segment : tregister);
  253. { overlay a registerlow }
  254. 2 : (registerlow : tregister);
  255. { overlay a 64 Bit register type }
  256. 3 : (reg64 : tregister64);
  257. 4 : (register64 : tregister64);
  258. );
  259. { it's only for better handling }
  260. LOC_MMXREGISTER,LOC_CMMXREGISTER : (mmxreg : tregister);
  261. end;
  262. {*****************************************************************************
  263. Constants
  264. *****************************************************************************}
  265. const
  266. max_operands = 4;
  267. {# Constant defining possibly all registers which might require saving }
  268. ALL_OTHERREGISTERS = [];
  269. general_superregisters = [RS_R0..RS_PC];
  270. {# Table of registers which can be allocated by the code generator
  271. internally, when generating the code.
  272. }
  273. { legend: }
  274. { xxxregs = set of all possibly used registers of that type in the code }
  275. { generator }
  276. { usableregsxxx = set of all 32bit components of registers that can be }
  277. { possible allocated to a regvar or using getregisterxxx (this }
  278. { excludes registers which can be only used for parameter }
  279. { passing on ABI's that define this) }
  280. { c_countusableregsxxx = amount of registers in the usableregsxxx set }
  281. maxintregs = 15;
  282. { to determine how many registers to use for regvars }
  283. maxintscratchregs = 3;
  284. usableregsint = [RS_R4..RS_R10];
  285. c_countusableregsint = 7;
  286. maxfpuregs = 8;
  287. fpuregs = [RS_F0..RS_F7];
  288. usableregsfpu = [RS_F4..RS_F7];
  289. c_countusableregsfpu = 4;
  290. mmregs = [RS_D0..RS_D15];
  291. usableregsmm = [RS_D8..RS_D15];
  292. c_countusableregsmm = 8;
  293. maxaddrregs = 0;
  294. addrregs = [];
  295. usableregsaddr = [];
  296. c_countusableregsaddr = 0;
  297. {*****************************************************************************
  298. Operand Sizes
  299. *****************************************************************************}
  300. type
  301. topsize = (S_NO,
  302. S_B,S_W,S_L,S_BW,S_BL,S_WL,
  303. S_IS,S_IL,S_IQ,
  304. S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
  305. );
  306. {*****************************************************************************
  307. Constants
  308. *****************************************************************************}
  309. const
  310. firstsaveintreg = RS_R4;
  311. lastsaveintreg = RS_R10;
  312. firstsavefpureg = RS_F4;
  313. lastsavefpureg = RS_F7;
  314. firstsavemmreg = RS_D8;
  315. lastsavemmreg = RS_D15;
  316. maxvarregs = 7;
  317. varregs : Array [1..maxvarregs] of tsuperregister =
  318. (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
  319. maxfpuvarregs = 4;
  320. fpuvarregs : Array [1..maxfpuvarregs] of tsuperregister =
  321. (RS_F4,RS_F5,RS_F6,RS_F7);
  322. {*****************************************************************************
  323. Default generic sizes
  324. *****************************************************************************}
  325. { Defines the default address size for a processor, }
  326. OS_ADDR = OS_32;
  327. { the natural int size for a processor, }
  328. OS_INT = OS_32;
  329. { the maximum float size for a processor, }
  330. OS_FLOAT = OS_F64;
  331. { the size of a vector register for a processor }
  332. OS_VECTOR = OS_M32;
  333. {*****************************************************************************
  334. Generic Register names
  335. *****************************************************************************}
  336. { Stack pointer register }
  337. NR_STACK_POINTER_REG = NR_R13;
  338. RS_STACK_POINTER_REG = RS_R13;
  339. { Frame pointer register }
  340. RS_FRAME_POINTER_REG = RS_R11;
  341. NR_FRAME_POINTER_REG = NR_R11;
  342. { Register for addressing absolute data in a position independant way,
  343. such as in PIC code. The exact meaning is ABI specific. For
  344. further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
  345. }
  346. NR_PIC_OFFSET_REG = NR_R9;
  347. { Results are returned in this register (32-bit values) }
  348. NR_FUNCTION_RETURN_REG = NR_R0;
  349. RS_FUNCTION_RETURN_REG = RS_R0;
  350. { Low part of 64bit return value }
  351. NR_FUNCTION_RETURN64_LOW_REG = NR_R0;
  352. RS_FUNCTION_RETURN64_LOW_REG = RS_R0;
  353. { High part of 64bit return value }
  354. NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
  355. RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
  356. { The value returned from a function is available in this register }
  357. NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
  358. RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
  359. { The lowh part of 64bit value returned from a function }
  360. NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
  361. RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
  362. { The high part of 64bit value returned from a function }
  363. NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
  364. RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
  365. NR_FPU_RESULT_REG = NR_F0;
  366. NR_MM_RESULT_REG = NR_NO;
  367. NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
  368. { Offset where the parent framepointer is pushed }
  369. PARENT_FRAMEPOINTER_OFFSET = 0;
  370. {*****************************************************************************
  371. GCC /ABI linking information
  372. *****************************************************************************}
  373. const
  374. { Registers which must be saved when calling a routine declared as
  375. cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
  376. saved should be the ones as defined in the target ABI and / or GCC.
  377. This value can be deduced from the CALLED_USED_REGISTERS array in the
  378. GCC source.
  379. }
  380. std_saved_registers = [RS_R4..RS_R10];
  381. { Required parameter alignment when calling a routine declared as
  382. stdcall and cdecl. The alignment value should be the one defined
  383. by GCC or the target ABI.
  384. The value of this constant is equal to the constant
  385. PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
  386. }
  387. std_param_align = 4;
  388. {*****************************************************************************
  389. Helpers
  390. *****************************************************************************}
  391. { Returns the tcgsize corresponding with the size of reg.}
  392. function reg_cgsize(const reg: tregister) : tcgsize;
  393. function cgsize2subreg(s:Tcgsize):Tsubregister;
  394. function is_calljmp(o:tasmop):boolean;
  395. procedure inverse_flags(var f: TResFlags);
  396. function flags_to_cond(const f: TResFlags) : TAsmCond;
  397. function findreg_by_number(r:Tregister):tregisterindex;
  398. function std_regnum_search(const s:string):Tregister;
  399. function std_regname(r:Tregister):string;
  400. procedure shifterop_reset(var so : tshifterop);
  401. function is_pc(const r : tregister) : boolean;
  402. implementation
  403. uses
  404. rgBase,verbose;
  405. const
  406. std_regname_table : array[tregisterindex] of string[7] = (
  407. {$i rarmstd.inc}
  408. );
  409. regnumber_index : array[tregisterindex] of tregisterindex = (
  410. {$i rarmrni.inc}
  411. );
  412. std_regname_index : array[tregisterindex] of tregisterindex = (
  413. {$i rarmsri.inc}
  414. );
  415. function cgsize2subreg(s:Tcgsize):Tsubregister;
  416. begin
  417. cgsize2subreg:=R_SUBWHOLE;
  418. end;
  419. function reg_cgsize(const reg: tregister): tcgsize;
  420. const subreg2cgsize:array[Tsubregister] of Tcgsize =
  421. (OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO);
  422. begin
  423. case getregtype(reg) of
  424. R_INTREGISTER :
  425. reg_cgsize:=OS_32;
  426. R_FPUREGISTER :
  427. reg_cgsize:=OS_F80;
  428. else
  429. internalerror(200303181);
  430. end;
  431. end;
  432. function is_calljmp(o:tasmop):boolean;
  433. begin
  434. { This isn't 100% perfect because the arm allows jumps also by writing to PC=R15.
  435. To overcome this problem we simply forbid that FPC generates jumps by loading R15 }
  436. is_calljmp:= o in [A_B,A_BL,A_BX,A_BLX];
  437. end;
  438. procedure inverse_flags(var f: TResFlags);
  439. const
  440. inv_flags: array[TResFlags] of TResFlags =
  441. (F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
  442. F_LT,F_GE,F_LE,F_GT);
  443. begin
  444. f:=inv_flags[f];
  445. end;
  446. function flags_to_cond(const f: TResFlags) : TAsmCond;
  447. const
  448. flag_2_cond: array[F_EQ..F_LE] of TAsmCond =
  449. (C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
  450. C_GE,C_LT,C_GT,C_LE);
  451. begin
  452. if f>high(flag_2_cond) then
  453. internalerror(200112301);
  454. result:=flag_2_cond[f];
  455. end;
  456. function findreg_by_number(r:Tregister):tregisterindex;
  457. begin
  458. result:=rgBase.findreg_by_number_table(r,regnumber_index);
  459. end;
  460. function std_regnum_search(const s:string):Tregister;
  461. begin
  462. result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
  463. end;
  464. function std_regname(r:Tregister):string;
  465. var
  466. p : tregisterindex;
  467. begin
  468. p:=findreg_by_number_table(r,regnumber_index);
  469. if p<>0 then
  470. result:=std_regname_table[p]
  471. else
  472. result:=generic_regname(r);
  473. end;
  474. procedure shifterop_reset(var so : tshifterop);
  475. begin
  476. FillChar(so,sizeof(so),0);
  477. end;
  478. function is_pc(const r : tregister) : boolean;
  479. begin
  480. is_pc:=(r=NR_R15);
  481. end;
  482. end.
  483. {
  484. $Log$
  485. Revision 1.31 2004-06-20 08:55:31 florian
  486. * logs truncated
  487. Revision 1.30 2004/06/16 20:07:10 florian
  488. * dwarf branch merged
  489. Revision 1.29.2.3 2004/06/13 10:51:17 florian
  490. * fixed several register allocator problems (sparc/arm)
  491. Revision 1.29.2.2 2004/06/12 17:01:01 florian
  492. * fixed compilation of arm compiler
  493. Revision 1.29.2.1 2004/05/01 11:12:23 florian
  494. * spilling of registers with size<>4 fixed
  495. Revision 1.29 2004/03/23 21:03:50 florian
  496. * arm assembler instructions can have 4 operands
  497. * qword comparisations fixed
  498. }