rautils.pas 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  4. This unit implements some support routines for assembler parsing
  5. independent of the processor
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. **********************************************************************}
  18. Unit RAUtils;
  19. {$i fpcdefs.inc}
  20. Interface
  21. Uses
  22. cutils,cclasses,
  23. globtype,aasmbase,aasmtai,cpubase,cpuinfo,cgbase,
  24. symconst,symbase,symtype,symdef,symsym;
  25. Const
  26. RPNMax = 10; { I think you only need 4, but just to be safe }
  27. OpMax = 25;
  28. {---------------------------------------------------------------------
  29. Local Label Management
  30. ---------------------------------------------------------------------}
  31. Type
  32. { Each local label has this structure associated with it }
  33. TLocalLabel = class(TNamedIndexItem)
  34. Emitted : boolean;
  35. constructor Create(const n:string);
  36. function Gettasmlabel:tasmlabel;
  37. private
  38. lab : tasmlabel;
  39. end;
  40. TLocalLabelList = class(TDictionary)
  41. procedure CheckEmitted;
  42. end;
  43. var
  44. LocalLabelList : TLocalLabelList;
  45. function CreateLocalLabel(const s: string; var hl: tasmlabel; emit:boolean):boolean;
  46. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  47. {---------------------------------------------------------------------
  48. Instruction management
  49. ---------------------------------------------------------------------}
  50. type
  51. TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
  52. OPR_REFERENCE,OPR_REGISTER,OPR_REGLIST,OPR_COND);
  53. TOprRec = record
  54. case typ:TOprType of
  55. OPR_NONE : ();
  56. OPR_CONSTANT : (val:longint);
  57. OPR_SYMBOL : (symbol:tasmsymbol;symofs:longint);
  58. OPR_REFERENCE : (ref:treference);
  59. OPR_LOCAL : (localsym:tvarsym;localsymofs:longint;localindexreg:tregister;localscale:byte;localgetoffset:boolean);
  60. OPR_REGISTER : (reg:tregister);
  61. {$ifdef m68k}
  62. OPR_REGLIST : (reglist:Tsupregset);
  63. {$endif m68k}
  64. {$ifdef powerpc}
  65. OPR_COND : (cond : tasmcond);
  66. {$endif m68k}
  67. end;
  68. TOperand = class
  69. hastype, { if the operand has typecasted variable }
  70. hasvar : boolean; { if the operand is loaded with a variable }
  71. size : TCGSize;
  72. opr : TOprRec;
  73. constructor create;virtual;
  74. destructor destroy;override;
  75. Procedure SetSize(_size:longint;force:boolean);virtual;
  76. Procedure SetCorrectSize(opcode:tasmop);virtual;
  77. Function SetupResult:boolean;virtual;
  78. Function SetupSelf:boolean;
  79. Function SetupOldEBP:boolean;
  80. Function SetupVar(const s:string;GetOffset : boolean): Boolean;
  81. Function SetupDirectVar(const hs:string): Boolean;
  82. Procedure InitRef;
  83. end;
  84. TCOperand = class of TOperand;
  85. TInstruction = class
  86. opcode : tasmop;
  87. condition : tasmcond;
  88. ops : byte;
  89. labeled : boolean;
  90. operands : array[1..max_operands] of toperand;
  91. constructor create(optype : tcoperand);virtual;
  92. destructor destroy;override;
  93. Procedure BuildOpcode;virtual;abstract;
  94. procedure ConcatInstruction(p:TAAsmoutput);virtual;
  95. Procedure Swapoperands;
  96. end;
  97. tstr2opentry = class(Tnamedindexitem)
  98. op: TAsmOp;
  99. end;
  100. {---------------------------------------------------------------------}
  101. { Expression parser types }
  102. {---------------------------------------------------------------------}
  103. TExprOperator = record
  104. ch: char; { operator }
  105. is_prefix: boolean; { was it a prefix, possible prefixes are +,- and not }
  106. end;
  107. String15 = String[15];
  108. {**********************************************************************}
  109. { The following operators are supported: }
  110. { '+' : addition }
  111. { '-' : subtraction }
  112. { '*' : multiplication }
  113. { '/' : modulo division }
  114. { '^' : exclusive or }
  115. { '<' : shift left }
  116. { '>' : shift right }
  117. { '&' : bitwise and }
  118. { '|' : bitwise or }
  119. { '~' : bitwise complement }
  120. { '%' : modulo division }
  121. { nnn: longint numbers }
  122. { ( and ) parenthesis }
  123. {**********************************************************************}
  124. TExprParse = class
  125. public
  126. Constructor create;
  127. Destructor Destroy;override;
  128. Function Evaluate(Expr: String): longint;
  129. Function Priority(_Operator: Char): longint;
  130. private
  131. RPNStack : Array[1..RPNMax] of longint; { Stack For RPN calculator }
  132. RPNTop : longint;
  133. OpStack : Array[1..OpMax] of TExprOperator; { Operator stack For conversion }
  134. OpTop : longint;
  135. Procedure RPNPush(Num: Longint);
  136. Function RPNPop: Longint;
  137. Procedure RPNCalc(token: String15; prefix: boolean);
  138. Procedure OpPush(_Operator: char; prefix: boolean);
  139. { In reality returns TExprOperaotr }
  140. Procedure OpPop(var _Operator:TExprOperator);
  141. end;
  142. { Evaluate an expression string to a longint }
  143. Function CalculateExpression(const expression: string): longint;
  144. {---------------------------------------------------------------------}
  145. { String routines }
  146. {---------------------------------------------------------------------}
  147. Function ValDecimal(const S:String):longint;
  148. Function ValOctal(const S:String):longint;
  149. Function ValBinary(const S:String):longint;
  150. Function ValHexaDecimal(const S:String):longint;
  151. Function PadZero(Var s: String; n: byte): Boolean;
  152. Function EscapeToPascal(const s:string): string;
  153. {---------------------------------------------------------------------
  154. Symbol helper routines
  155. ---------------------------------------------------------------------}
  156. procedure AsmSearchSym(const s:string;var srsym:tsym;var srsymtable:tsymtable);
  157. Function GetRecordOffsetSize(s:string;Var Offset: longint;var Size:longint):boolean;
  158. Function SearchType(const hs:string;var size:longint): Boolean;
  159. Function SearchRecordType(const s:string): boolean;
  160. Function SearchIConstant(const s:string; var l:longint): boolean;
  161. {---------------------------------------------------------------------
  162. Instruction generation routines
  163. ---------------------------------------------------------------------}
  164. Procedure ConcatPasString(p : TAAsmoutput;s:string);
  165. Procedure ConcatDirect(p : TAAsmoutput;s:string);
  166. Procedure ConcatLabel(p: TAAsmoutput;var l : tasmlabel);
  167. Procedure ConcatConstant(p : TAAsmoutput;value: longint; maxvalue: longint);
  168. Procedure ConcatConstSymbol(p : TAAsmoutput;const sym:string;l:longint);
  169. Procedure ConcatRealConstant(p : TAAsmoutput;value: bestreal; real_typ : tfloattype);
  170. Procedure ConcatString(p : TAAsmoutput;s:string);
  171. procedure ConcatAlign(p:TAAsmoutput;l:longint);
  172. Procedure ConcatPublic(p:TAAsmoutput;const s : string);
  173. Procedure ConcatLocal(p:TAAsmoutput;const s : string);
  174. Procedure ConcatGlobalBss(const s : string;size : longint);
  175. Procedure ConcatLocalBss(const s : string;size : longint);
  176. Implementation
  177. uses
  178. {$ifdef delphi}
  179. sysutils,
  180. {$else}
  181. strings,
  182. {$endif}
  183. defutil,systems,verbose,globals,
  184. symtable,paramgr,
  185. aasmcpu,
  186. procinfo;
  187. {*************************************************************************
  188. TExprParse
  189. *************************************************************************}
  190. Constructor TExprParse.create;
  191. Begin
  192. end;
  193. Procedure TExprParse.RPNPush(Num : longint);
  194. { Add an operand to the top of the RPN stack }
  195. begin
  196. if RPNTop < RPNMax then
  197. begin
  198. Inc(RPNTop);
  199. RPNStack[RPNTop]:=Num;
  200. end
  201. else
  202. Message(asmr_e_expr_illegal);
  203. end;
  204. Function TExprParse.RPNPop : longint;
  205. { Get the operand at the top of the RPN stack }
  206. begin
  207. if RPNTop > 0 then
  208. begin
  209. RPNPop:=RPNStack[RPNTop];
  210. Dec(RPNTop);
  211. end
  212. else
  213. Message(asmr_e_expr_illegal);
  214. end;
  215. Procedure TExprParse.RPNCalc(Token : String15; prefix:boolean); { RPN Calculator }
  216. Var
  217. Temp : longint;
  218. n1,n2 : longint;
  219. LocalError : Integer;
  220. begin
  221. { Handle operators }
  222. if (Length(Token) = 1) and (Token[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then
  223. Case Token[1] of
  224. '+' :
  225. Begin
  226. if not prefix then
  227. RPNPush(RPNPop + RPNPop);
  228. end;
  229. '-' :
  230. Begin
  231. if prefix then
  232. RPNPush(-(RPNPop))
  233. else
  234. begin
  235. n1:=RPNPop;
  236. n2:=RPNPop;
  237. RPNPush(n2 - n1);
  238. end;
  239. end;
  240. '*' : RPNPush(RPNPop * RPNPop);
  241. '&' :
  242. begin
  243. n1:=RPNPop;
  244. n2:=RPNPop;
  245. RPNPush(n2 and n1);
  246. end;
  247. '|' :
  248. begin
  249. n1:=RPNPop;
  250. n2:=RPNPop;
  251. RPNPush(n2 or n1);
  252. end;
  253. '~' : RPNPush(NOT RPNPop);
  254. '<' :
  255. begin
  256. n1:=RPNPop;
  257. n2:=RPNPop;
  258. RPNPush(n2 SHL n1);
  259. end;
  260. '>' :
  261. begin
  262. n1:=RPNPop;
  263. n2:=RPNPop;
  264. RPNPush(n2 SHR n1);
  265. end;
  266. '%' :
  267. begin
  268. Temp:=RPNPop;
  269. if Temp <> 0 then
  270. RPNPush(RPNPop mod Temp)
  271. else
  272. begin
  273. Message(asmr_e_expr_zero_divide);
  274. { push 1 for error recovery }
  275. RPNPush(1);
  276. end;
  277. end;
  278. '^' : RPNPush(RPNPop XOR RPNPop);
  279. '/' :
  280. begin
  281. Temp:=RPNPop;
  282. if Temp <> 0 then
  283. RPNPush(RPNPop div Temp)
  284. else
  285. begin
  286. Message(asmr_e_expr_zero_divide);
  287. { push 1 for error recovery }
  288. RPNPush(1);
  289. end;
  290. end;
  291. end
  292. else
  293. begin
  294. { Convert String to number and add to stack }
  295. Val(Token, Temp, LocalError);
  296. if LocalError = 0 then
  297. RPNPush(Temp)
  298. else
  299. begin
  300. Message(asmr_e_expr_illegal);
  301. { push 1 for error recovery }
  302. RPNPush(1);
  303. end;
  304. end;
  305. end;
  306. Procedure TExprParse.OpPush(_Operator : char;prefix: boolean);
  307. { Add an operator onto top of the stack }
  308. begin
  309. if OpTop < OpMax then
  310. begin
  311. Inc(OpTop);
  312. OpStack[OpTop].ch:=_Operator;
  313. OpStack[OpTop].is_prefix:=prefix;
  314. end
  315. else
  316. Message(asmr_e_expr_illegal);
  317. end;
  318. Procedure TExprParse.OpPop(var _Operator:TExprOperator);
  319. { Get operator at the top of the stack }
  320. begin
  321. if OpTop > 0 then
  322. begin
  323. _Operator:=OpStack[OpTop];
  324. Dec(OpTop);
  325. end
  326. else
  327. Message(asmr_e_expr_illegal);
  328. end;
  329. Function TExprParse.Priority(_Operator : Char) : longint;
  330. { Return priority of operator }
  331. { The greater the priority, the higher the precedence }
  332. begin
  333. Case _Operator OF
  334. '(' :
  335. Priority:=0;
  336. '+', '-' :
  337. Priority:=1;
  338. '*', '/','%','<','>' :
  339. Priority:=2;
  340. '|','&','^','~' :
  341. Priority:=0;
  342. else
  343. Message(asmr_e_expr_illegal);
  344. end;
  345. end;
  346. Function TExprParse.Evaluate(Expr : String):longint;
  347. Var
  348. I : LongInt;
  349. Token : String15;
  350. opr : TExprOperator;
  351. begin
  352. Evaluate:=0;
  353. { Reset stacks }
  354. OpTop :=0;
  355. RPNTop:=0;
  356. Token :='';
  357. { nothing to do ? }
  358. if Expr='' then
  359. exit;
  360. For I:=1 to Length(Expr) DO
  361. begin
  362. if Expr[I] in ['0'..'9'] then
  363. begin { Build multi-digit numbers }
  364. Token:=Token + Expr[I];
  365. if I = Length(Expr) then { Send last one to calculator }
  366. RPNCalc(Token,false);
  367. end
  368. else
  369. if Expr[I] in ['+', '-', '*', '/', '(', ')','^','&','|','%','~','<','>'] then
  370. begin
  371. if Token <> '' then
  372. begin { Send last built number to calc. }
  373. RPNCalc(Token,false);
  374. Token:='';
  375. end;
  376. Case Expr[I] OF
  377. '(' : OpPush('(',false);
  378. ')' : begin
  379. While OpStack[OpTop].ch <> '(' DO
  380. Begin
  381. OpPop(opr);
  382. RPNCalc(opr.ch,opr.is_prefix);
  383. end;
  384. OpPop(opr); { Pop off and ignore the '(' }
  385. end;
  386. '+','-','~' : Begin
  387. { workaround for -2147483648 }
  388. if (expr[I]='-') and (expr[i+1] in ['0'..'9']) then
  389. begin
  390. token:='-';
  391. expr[i]:='+';
  392. end;
  393. { if start of expression then surely a prefix }
  394. { or if previous char was also an operator }
  395. if (I = 1) or (not (Expr[I-1] in ['0'..'9','(',')'])) then
  396. OpPush(Expr[I],true)
  397. else
  398. Begin
  399. { Evaluate all higher priority operators }
  400. While (OpTop > 0) AND (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  401. Begin
  402. OpPop(opr);
  403. RPNCalc(opr.ch,opr.is_prefix);
  404. end;
  405. OpPush(Expr[I],false);
  406. End;
  407. end;
  408. '*', '/',
  409. '^','|','&',
  410. '%','<','>' : begin
  411. While (OpTop > 0) and (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  412. Begin
  413. OpPop(opr);
  414. RPNCalc(opr.ch,opr.is_prefix);
  415. end;
  416. OpPush(Expr[I],false);
  417. end;
  418. end; { Case }
  419. end
  420. else
  421. Message(asmr_e_expr_illegal); { Handle bad input error }
  422. end;
  423. { Pop off the remaining operators }
  424. While OpTop > 0 do
  425. Begin
  426. OpPop(opr);
  427. RPNCalc(opr.ch,opr.is_prefix);
  428. end;
  429. { The result is stored on the top of the stack }
  430. Evaluate:=RPNPop;
  431. end;
  432. Destructor TExprParse.Destroy;
  433. Begin
  434. end;
  435. Function CalculateExpression(const expression: string): longint;
  436. var
  437. expr: TExprParse;
  438. Begin
  439. expr:=TExprParse.create;
  440. CalculateExpression:=expr.Evaluate(expression);
  441. expr.Free;
  442. end;
  443. {*************************************************************************}
  444. { String conversions/utils }
  445. {*************************************************************************}
  446. Function EscapeToPascal(const s:string): string;
  447. { converts a C styled string - which contains escape }
  448. { characters to a pascal style string. }
  449. var
  450. i,len : longint;
  451. hs : string;
  452. temp : string;
  453. c : char;
  454. Begin
  455. hs:='';
  456. len:=0;
  457. i:=0;
  458. while (i<length(s)) and (len<255) do
  459. begin
  460. Inc(i);
  461. if (s[i]='\') and (i<length(s)) then
  462. Begin
  463. inc(i);
  464. case s[i] of
  465. '\' :
  466. c:='\';
  467. 'b':
  468. c:=#8;
  469. 'f':
  470. c:=#12;
  471. 'n':
  472. c:=#10;
  473. 'r':
  474. c:=#13;
  475. 't':
  476. c:=#9;
  477. '"':
  478. c:='"';
  479. '0'..'7':
  480. Begin
  481. temp:=s[i];
  482. temp:=temp+s[i+1];
  483. temp:=temp+s[i+2];
  484. inc(i,2);
  485. c:=chr(ValOctal(temp));
  486. end;
  487. 'x':
  488. Begin
  489. temp:=s[i+1];
  490. temp:=temp+s[i+2];
  491. inc(i,2);
  492. c:=chr(ValHexaDecimal(temp));
  493. end;
  494. else
  495. Begin
  496. Message1(asmr_e_escape_seq_ignored,s[i]);
  497. c:=s[i];
  498. end;
  499. end;
  500. end
  501. else
  502. c:=s[i];
  503. inc(len);
  504. hs[len]:=c;
  505. end;
  506. hs[0]:=chr(len);
  507. EscapeToPascal:=hs;
  508. end;
  509. Function ValDecimal(const S:String):longint;
  510. { Converts a decimal string to longint }
  511. var
  512. vs,c : longint;
  513. Begin
  514. vs:=0;
  515. for c:=1 to length(s) do
  516. begin
  517. vs:=vs*10;
  518. if s[c] in ['0'..'9'] then
  519. inc(vs,ord(s[c])-ord('0'))
  520. else
  521. begin
  522. Message1(asmr_e_error_converting_decimal,s);
  523. ValDecimal:=0;
  524. exit;
  525. end;
  526. end;
  527. ValDecimal:=vs;
  528. end;
  529. Function ValOctal(const S:String):longint;
  530. { Converts an octal string to longint }
  531. var
  532. vs,c : longint;
  533. Begin
  534. vs:=0;
  535. for c:=1 to length(s) do
  536. begin
  537. vs:=vs shl 3;
  538. if s[c] in ['0'..'7'] then
  539. inc(vs,ord(s[c])-ord('0'))
  540. else
  541. begin
  542. Message1(asmr_e_error_converting_octal,s);
  543. ValOctal:=0;
  544. exit;
  545. end;
  546. end;
  547. ValOctal:=vs;
  548. end;
  549. Function ValBinary(const S:String):longint;
  550. { Converts a binary string to longint }
  551. var
  552. vs,c : longint;
  553. Begin
  554. vs:=0;
  555. for c:=1 to length(s) do
  556. begin
  557. vs:=vs shl 1;
  558. if s[c] in ['0'..'1'] then
  559. inc(vs,ord(s[c])-ord('0'))
  560. else
  561. begin
  562. Message1(asmr_e_error_converting_binary,s);
  563. ValBinary:=0;
  564. exit;
  565. end;
  566. end;
  567. ValBinary:=vs;
  568. end;
  569. Function ValHexadecimal(const S:String):longint;
  570. { Converts a binary string to longint }
  571. var
  572. vs,c : longint;
  573. Begin
  574. vs:=0;
  575. for c:=1 to length(s) do
  576. begin
  577. vs:=vs shl 4;
  578. case s[c] of
  579. '0'..'9' :
  580. inc(vs,ord(s[c])-ord('0'));
  581. 'A'..'F' :
  582. inc(vs,ord(s[c])-ord('A')+10);
  583. 'a'..'f' :
  584. inc(vs,ord(s[c])-ord('a')+10);
  585. else
  586. begin
  587. Message1(asmr_e_error_converting_hexadecimal,s);
  588. ValHexadecimal:=0;
  589. exit;
  590. end;
  591. end;
  592. end;
  593. ValHexadecimal:=vs;
  594. end;
  595. Function PadZero(Var s: String; n: byte): Boolean;
  596. Begin
  597. PadZero:=TRUE;
  598. { Do some error checking first }
  599. if Length(s) = n then
  600. exit
  601. else
  602. if Length(s) > n then
  603. Begin
  604. PadZero:=FALSE;
  605. delete(s,n+1,length(s));
  606. exit;
  607. end
  608. else
  609. PadZero:=TRUE;
  610. { Fill it up with the specified character }
  611. fillchar(s[length(s)+1],n-1,#0);
  612. s[0]:=chr(n);
  613. end;
  614. {****************************************************************************
  615. TOperand
  616. ****************************************************************************}
  617. constructor TOperand.Create;
  618. begin
  619. size:=OS_NO;
  620. hastype:=false;
  621. hasvar:=false;
  622. FillChar(Opr,sizeof(Opr),0);
  623. end;
  624. destructor TOperand.destroy;
  625. begin
  626. end;
  627. Procedure TOperand.SetSize(_size:longint;force:boolean);
  628. begin
  629. if force or
  630. ((size = OS_NO) and (_size<=extended_size)) then
  631. Begin
  632. case _size of
  633. 1 : size:=OS_8;
  634. 2 : size:=OS_16{ could be S_IS};
  635. 4 : size:=OS_32{ could be S_IL or S_FS};
  636. 8 : size:=OS_64{ could be S_D or S_FL};
  637. else
  638. begin
  639. { extended_size can also be 8, resulting in a
  640. duplicate label }
  641. if _size=extended_size then
  642. size:=OS_F80;
  643. end;
  644. end;
  645. end;
  646. end;
  647. Procedure TOperand.SetCorrectSize(opcode:tasmop);
  648. begin
  649. end;
  650. Function TOperand.SetupResult:boolean;
  651. Begin
  652. SetupResult:=false;
  653. { replace by correct offset. }
  654. if (not is_void(current_procinfo.procdef.rettype.def)) then
  655. begin
  656. if (m_tp7 in aktmodeswitches) and
  657. (not paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption)) then
  658. begin
  659. Message(asmr_e_cannot_use_RESULT_here);
  660. exit;
  661. end;
  662. SetupResult:=setupvar('result',false)
  663. end
  664. else
  665. Message(asmr_e_void_function);
  666. end;
  667. Function TOperand.SetupSelf:boolean;
  668. Begin
  669. SetupSelf:=false;
  670. if assigned(current_procinfo.procdef._class) then
  671. SetupSelf:=setupvar('self',false)
  672. else
  673. Message(asmr_e_cannot_use_SELF_outside_a_method);
  674. end;
  675. Function TOperand.SetupOldEBP:boolean;
  676. Begin
  677. SetupOldEBP:=false;
  678. if current_procinfo.procdef.parast.symtablelevel>normal_function_level then
  679. SetupOldEBP:=setupvar('parentframe',false)
  680. else
  681. Message(asmr_e_cannot_use_OLDEBP_outside_nested_procedure);
  682. end;
  683. Function TOperand.SetupVar(const s:string;GetOffset : boolean): Boolean;
  684. function symtable_has_varsyms(st:tsymtable):boolean;
  685. var
  686. sym : tsym;
  687. begin
  688. result:=false;
  689. sym:=tsym(st.symindex.first);
  690. while assigned(sym) do
  691. begin
  692. if sym.typ=varsym then
  693. begin
  694. result:=true;
  695. exit;
  696. end;
  697. sym:=tsym(sym.indexnext);
  698. end;
  699. end;
  700. procedure setconst(l:longint);
  701. begin
  702. { We return the address of the field, just like Delphi/TP }
  703. case opr.typ of
  704. OPR_NONE :
  705. begin
  706. opr.typ:=OPR_CONSTANT;
  707. opr.val:=l;
  708. end;
  709. OPR_CONSTANT :
  710. inc(opr.val,l);
  711. OPR_REFERENCE :
  712. inc(opr.ref.offset,l);
  713. OPR_LOCAL :
  714. inc(opr.localsymofs,l);
  715. else
  716. Message(asmr_e_invalid_operand_type);
  717. end;
  718. end;
  719. { search and sets up the correct fields in the Instr record }
  720. { for the NON-constant identifier passed to the routine. }
  721. { if not found returns FALSE. }
  722. var
  723. sym : tsym;
  724. srsymtable : tsymtable;
  725. harrdef : tarraydef;
  726. indexreg : tregister;
  727. l : longint;
  728. plist : psymlistitem;
  729. Begin
  730. SetupVar:=false;
  731. asmsearchsym(s,sym,srsymtable);
  732. if sym = nil then
  733. exit;
  734. if sym.typ=absolutesym then
  735. begin
  736. if (tabsolutesym(sym).abstyp=tovar) then
  737. begin
  738. { Only support simple loads }
  739. plist:=tabsolutesym(sym).ref.firstsym;
  740. if assigned(plist) and
  741. (plist^.sltype=sl_load) then
  742. sym:=plist^.sym
  743. else
  744. begin
  745. Message(asmr_e_unsupported_symbol_type);
  746. exit;
  747. end;
  748. end
  749. else
  750. begin
  751. Message(asmr_e_unsupported_symbol_type);
  752. exit;
  753. end;
  754. end;
  755. case sym.typ of
  756. varsym :
  757. begin
  758. { we always assume in asm statements that }
  759. { that the variable is valid. }
  760. tvarsym(sym).varstate:=vs_used;
  761. inc(tvarsym(sym).refs);
  762. case tvarsym(sym).owner.symtabletype of
  763. objectsymtable :
  764. begin
  765. setconst(tvarsym(sym).fieldoffset);
  766. hasvar:=true;
  767. SetupVar:=true;
  768. Exit;
  769. end;
  770. globalsymtable,
  771. staticsymtable :
  772. begin
  773. initref;
  774. opr.ref.symbol:=objectlibrary.newasmsymboldata(tvarsym(sym).mangledname);
  775. end;
  776. parasymtable,
  777. localsymtable :
  778. begin
  779. if (vo_is_external in tvarsym(sym).varoptions) then
  780. begin
  781. initref;
  782. opr.ref.symbol:=objectlibrary.newasmsymboldata(tvarsym(sym).mangledname)
  783. end
  784. else
  785. begin
  786. if opr.typ=OPR_REFERENCE then
  787. begin
  788. indexreg:=opr.ref.base;
  789. if opr.ref.index<>NR_NO then
  790. begin
  791. if indexreg=NR_NO then
  792. indexreg:=opr.ref.index
  793. else
  794. Message(asmr_e_multiple_index);
  795. end;
  796. end
  797. else
  798. indexreg:=NR_NO;
  799. opr.typ:=OPR_LOCAL;
  800. if assigned(current_procinfo.parent) and
  801. (current_procinfo.procdef.proccalloption<>pocall_inline) and
  802. (tvarsym(sym).owner<>current_procinfo.procdef.localst) and
  803. (tvarsym(sym).owner<>current_procinfo.procdef.parast) and
  804. (current_procinfo.procdef.localst.symtablelevel>normal_function_level) and
  805. symtable_has_varsyms(current_procinfo.procdef.localst) then
  806. message1(asmr_e_local_para_unreachable,s);
  807. opr.localsym:=tvarsym(sym);
  808. opr.localsymofs:=0;
  809. opr.localindexreg:=indexreg;
  810. opr.localscale:=0;
  811. opr.localgetoffset:=GetOffset;
  812. end;
  813. if paramanager.push_addr_param(tvarsym(sym).varspez,tvarsym(sym).vartype.def,current_procinfo.procdef.proccalloption) then
  814. SetSize(pointer_size,false);
  815. end;
  816. end;
  817. case tvarsym(sym).vartype.def.deftype of
  818. orddef,
  819. enumdef,
  820. pointerdef,
  821. floatdef :
  822. SetSize(tvarsym(sym).getsize,false);
  823. arraydef :
  824. begin
  825. { for arrays try to get the element size, take care of
  826. multiple indexes }
  827. harrdef:=tarraydef(tvarsym(sym).vartype.def);
  828. while assigned(harrdef.elementtype.def) and
  829. (harrdef.elementtype.def.deftype=arraydef) do
  830. harrdef:=tarraydef(harrdef.elementtype.def);
  831. SetSize(harrdef.elesize,false);
  832. end;
  833. end;
  834. hasvar:=true;
  835. SetupVar:=true;
  836. Exit;
  837. end;
  838. typedconstsym :
  839. begin
  840. initref;
  841. opr.ref.symbol:=objectlibrary.newasmsymboldata(ttypedconstsym(sym).mangledname);
  842. case ttypedconstsym(sym).typedconsttype.def.deftype of
  843. orddef,
  844. enumdef,
  845. pointerdef,
  846. floatdef :
  847. SetSize(ttypedconstsym(sym).getsize,false);
  848. arraydef :
  849. begin
  850. { for arrays try to get the element size, take care of
  851. multiple indexes }
  852. harrdef:=tarraydef(ttypedconstsym(sym).typedconsttype.def);
  853. while assigned(harrdef.elementtype.def) and
  854. (harrdef.elementtype.def.deftype=arraydef) do
  855. harrdef:=tarraydef(harrdef.elementtype.def);
  856. SetSize(harrdef.elesize,false);
  857. end;
  858. end;
  859. hasvar:=true;
  860. SetupVar:=true;
  861. Exit;
  862. end;
  863. constsym :
  864. begin
  865. if tconstsym(sym).consttyp in [constint,constchar,constbool] then
  866. begin
  867. setconst(tconstsym(sym).value.valueord);
  868. SetupVar:=true;
  869. Exit;
  870. end;
  871. end;
  872. typesym :
  873. begin
  874. if ttypesym(sym).restype.def.deftype in [recorddef,objectdef] then
  875. begin
  876. setconst(0);
  877. SetupVar:=TRUE;
  878. Exit;
  879. end;
  880. end;
  881. procsym :
  882. begin
  883. if opr.typ<>OPR_NONE then
  884. Message(asmr_e_invalid_operand_type);
  885. if Tprocsym(sym).procdef_count>1 then
  886. Message(asmr_w_calling_overload_func);
  887. l:=opr.ref.offset;
  888. opr.typ:=OPR_SYMBOL;
  889. opr.symbol:=objectlibrary.newasmsymbol(tprocsym(sym).first_procdef.mangledname);
  890. opr.symofs:=l;
  891. hasvar:=true;
  892. SetupVar:=TRUE;
  893. Exit;
  894. end;
  895. else
  896. begin
  897. Message(asmr_e_unsupported_symbol_type);
  898. exit;
  899. end;
  900. end;
  901. end;
  902. { looks for internal names of variables and routines }
  903. Function TOperand.SetupDirectVar(const hs:string): Boolean;
  904. var
  905. p : tasmsymbol;
  906. begin
  907. SetupDirectVar:=false;
  908. p:=objectlibrary.getasmsymbol(hs);
  909. if assigned(p) then
  910. begin
  911. InitRef;
  912. opr.ref.symbol:=p;
  913. hasvar:=true;
  914. SetupDirectVar:=true;
  915. end;
  916. end;
  917. procedure TOperand.InitRef;
  918. {*********************************************************************}
  919. { Description: This routine first check if the opcode is of }
  920. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  921. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  922. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  923. { to point to the default segment. }
  924. {*********************************************************************}
  925. var
  926. l : longint;
  927. Begin
  928. case opr.typ of
  929. OPR_REFERENCE :
  930. exit;
  931. OPR_CONSTANT :
  932. begin
  933. l:=opr.val;
  934. opr.typ:=OPR_REFERENCE;
  935. Fillchar(opr.ref,sizeof(treference),0);
  936. opr.Ref.Offset:=l;
  937. end;
  938. OPR_NONE :
  939. begin
  940. opr.typ:=OPR_REFERENCE;
  941. Fillchar(opr.ref,sizeof(treference),0);
  942. end;
  943. else
  944. begin
  945. Message(asmr_e_invalid_operand_type);
  946. { Recover }
  947. opr.typ:=OPR_REFERENCE;
  948. Fillchar(opr.ref,sizeof(treference),0);
  949. end;
  950. end;
  951. end;
  952. {****************************************************************************
  953. TInstruction
  954. ****************************************************************************}
  955. constructor TInstruction.create(optype : tcoperand);
  956. var
  957. i : longint;
  958. Begin
  959. { these field are set to 0 anyways by the constructor helper (FK)
  960. Opcode:=A_NONE;
  961. Condition:=C_NONE;
  962. Ops:=0;
  963. }
  964. for i:=1 to max_operands do
  965. Operands[i]:=optype.create;
  966. Labeled:=false;
  967. end;
  968. destructor TInstruction.destroy;
  969. var
  970. i : longint;
  971. Begin
  972. for i:=1 to max_operands do
  973. Operands[i].free;
  974. end;
  975. Procedure TInstruction.Swapoperands;
  976. Var
  977. p : toperand;
  978. Begin
  979. case Ops of
  980. 2 :
  981. begin
  982. p:=Operands[1];
  983. Operands[1]:=Operands[2];
  984. Operands[2]:=p;
  985. end;
  986. 3 :
  987. begin
  988. p:=Operands[1];
  989. Operands[1]:=Operands[3];
  990. Operands[3]:=p;
  991. end;
  992. end;
  993. end;
  994. procedure TInstruction.ConcatInstruction(p:TAAsmoutput);
  995. var
  996. ai : taicpu;
  997. i : longint;
  998. begin
  999. ai:=taicpu.op_none(opcode);
  1000. ai.Ops:=Ops;
  1001. ai.Allocate_oper(Ops);
  1002. for i:=1 to Ops do
  1003. begin
  1004. case operands[i].opr.typ of
  1005. OPR_CONSTANT :
  1006. ai.loadconst(i-1,aword(operands[i].opr.val));
  1007. OPR_REGISTER:
  1008. ai.loadreg(i-1,operands[i].opr.reg);
  1009. OPR_SYMBOL:
  1010. ai.loadsymbol(i-1,operands[i].opr.symbol,operands[i].opr.symofs);
  1011. OPR_LOCAL :
  1012. ai.loadlocal(i-1,operands[i].opr.localsym,operands[i].opr.localsymofs,operands[i].opr.localindexreg,
  1013. operands[i].opr.localscale,operands[i].opr.localgetoffset);
  1014. OPR_REFERENCE:
  1015. ai.loadref(i-1,operands[i].opr.ref);
  1016. end;
  1017. end;
  1018. ai.SetCondition(condition);
  1019. { Concat the opcode or give an error }
  1020. if assigned(ai) then
  1021. p.concat(ai)
  1022. else
  1023. Message(asmr_e_invalid_opcode_and_operand);
  1024. end;
  1025. {***************************************************************************
  1026. TLocalLabel
  1027. ***************************************************************************}
  1028. constructor TLocalLabel.create(const n:string);
  1029. begin
  1030. inherited CreateName(n);
  1031. lab:=nil;
  1032. emitted:=false;
  1033. end;
  1034. function TLocalLabel.Gettasmlabel:tasmlabel;
  1035. begin
  1036. if not assigned(lab) then
  1037. begin
  1038. objectlibrary.getlabel(lab);
  1039. { this label is forced to be used so it's always written }
  1040. lab.increfs;
  1041. end;
  1042. Gettasmlabel:=lab;
  1043. end;
  1044. {***************************************************************************
  1045. TLocalLabelList
  1046. ***************************************************************************}
  1047. procedure LocalLabelEmitted(p:tnamedindexitem;arg:pointer);
  1048. begin
  1049. if not TLocalLabel(p).emitted then
  1050. Message1(asmr_e_unknown_label_identifier,p.name);
  1051. end;
  1052. procedure TLocalLabelList.CheckEmitted;
  1053. begin
  1054. ForEach_Static({$ifdef FPCPROCVAR}@{$endif}LocalLabelEmitted,nil)
  1055. end;
  1056. function CreateLocalLabel(const s: string; var hl: tasmlabel; emit:boolean):boolean;
  1057. var
  1058. lab : TLocalLabel;
  1059. Begin
  1060. CreateLocalLabel:=true;
  1061. { Check if it already is defined }
  1062. lab:=TLocalLabel(LocalLabellist.Search(s));
  1063. if not assigned(lab) then
  1064. begin
  1065. lab:=TLocalLabel.Create(s);
  1066. LocalLabellist.Insert(lab);
  1067. end;
  1068. { set emitted flag and check for dup syms }
  1069. if emit then
  1070. begin
  1071. if lab.Emitted then
  1072. begin
  1073. Message1(asmr_e_dup_local_sym,lab.Name);
  1074. CreateLocalLabel:=false;
  1075. end;
  1076. lab.Emitted:=true;
  1077. end;
  1078. hl:=lab.Gettasmlabel;
  1079. end;
  1080. {****************************************************************************
  1081. Symbol table helper routines
  1082. ****************************************************************************}
  1083. procedure AsmSearchSym(const s:string;var srsym:tsym;var srsymtable:tsymtable);
  1084. var
  1085. i : integer;
  1086. begin
  1087. i:=pos('.',s);
  1088. { allow unit.identifier }
  1089. if i>0 then
  1090. begin
  1091. searchsym(Copy(s,1,i-1),srsym,srsymtable);
  1092. if assigned(srsym) then
  1093. begin
  1094. if (srsym.typ=unitsym) and
  1095. (srsym.owner.unitid=0) then
  1096. srsym:=searchsymonlyin(tunitsym(srsym).unitsymtable,Copy(s,i+1,255))
  1097. else
  1098. srsym:=nil;
  1099. end;
  1100. end
  1101. else
  1102. searchsym(s,srsym,srsymtable);
  1103. end;
  1104. Function SearchType(const hs:string;var size:longint): Boolean;
  1105. var
  1106. srsym : tsym;
  1107. srsymtable : tsymtable;
  1108. begin
  1109. result:=false;
  1110. size:=0;
  1111. asmsearchsym(hs,srsym,srsymtable);
  1112. if assigned(srsym) and
  1113. (srsym.typ=typesym) then
  1114. begin
  1115. size:=ttypesym(srsym).restype.def.size;
  1116. result:=true;
  1117. end;
  1118. end;
  1119. Function SearchRecordType(const s:string): boolean;
  1120. var
  1121. srsym : tsym;
  1122. srsymtable : tsymtable;
  1123. Begin
  1124. SearchRecordType:=false;
  1125. { Check the constants in symtable }
  1126. asmsearchsym(s,srsym,srsymtable);
  1127. if srsym <> nil then
  1128. Begin
  1129. case srsym.typ of
  1130. typesym :
  1131. begin
  1132. if ttypesym(srsym).restype.def.deftype in [recorddef,objectdef] then
  1133. begin
  1134. SearchRecordType:=true;
  1135. exit;
  1136. end;
  1137. end;
  1138. end;
  1139. end;
  1140. end;
  1141. Function SearchIConstant(const s:string; var l:longint): boolean;
  1142. {**********************************************************************}
  1143. { Description: Searches for a CONSTANT of name s in either the local }
  1144. { symbol list, then in the global symbol list, and returns the value }
  1145. { of that constant in l. Returns TRUE if successfull, if not found, }
  1146. { or if the constant is not of correct type, then returns FALSE }
  1147. { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  1148. { respectively. }
  1149. {**********************************************************************}
  1150. var
  1151. srsym : tsym;
  1152. srsymtable : tsymtable;
  1153. Begin
  1154. SearchIConstant:=false;
  1155. { check for TRUE or FALSE reserved words first }
  1156. if s = 'TRUE' then
  1157. Begin
  1158. SearchIConstant:=TRUE;
  1159. l:=1;
  1160. exit;
  1161. end;
  1162. if s = 'FALSE' then
  1163. Begin
  1164. SearchIConstant:=TRUE;
  1165. l:=0;
  1166. exit;
  1167. end;
  1168. { Check the constants in symtable }
  1169. asmsearchsym(s,srsym,srsymtable);
  1170. if srsym <> nil then
  1171. Begin
  1172. case srsym.typ of
  1173. constsym :
  1174. begin
  1175. if (tconstsym(srsym).consttyp in [constord,constint,constchar,constbool]) then
  1176. Begin
  1177. l:=tconstsym(srsym).value.valueord;
  1178. SearchIConstant:=TRUE;
  1179. exit;
  1180. end;
  1181. end;
  1182. enumsym:
  1183. Begin
  1184. l:=tenumsym(srsym).value;
  1185. SearchIConstant:=TRUE;
  1186. exit;
  1187. end;
  1188. end;
  1189. end;
  1190. end;
  1191. Function GetRecordOffsetSize(s:string;Var Offset: longint;var Size:longint):boolean;
  1192. { search and returns the offset and size of records/objects of the base }
  1193. { with field name setup in field. }
  1194. { returns FALSE if not found. }
  1195. { used when base is a variable or a typed constant name. }
  1196. var
  1197. st : tsymtable;
  1198. harrdef : tarraydef;
  1199. sym : tsym;
  1200. srsymtable : tsymtable;
  1201. i : longint;
  1202. base : string;
  1203. Begin
  1204. GetRecordOffsetSize:=FALSE;
  1205. Offset:=0;
  1206. Size:=0;
  1207. i:=pos('.',s);
  1208. if i=0 then
  1209. i:=255;
  1210. base:=Copy(s,1,i-1);
  1211. delete(s,1,i);
  1212. if base='SELF' then
  1213. st:=current_procinfo.procdef._class.symtable
  1214. else
  1215. begin
  1216. asmsearchsym(base,sym,srsymtable);
  1217. st:=nil;
  1218. { we can start with a var,type,typedconst }
  1219. case sym.typ of
  1220. varsym :
  1221. begin
  1222. case tvarsym(sym).vartype.def.deftype of
  1223. recorddef :
  1224. st:=trecorddef(tvarsym(sym).vartype.def).symtable;
  1225. objectdef :
  1226. st:=tobjectdef(tvarsym(sym).vartype.def).symtable;
  1227. end;
  1228. end;
  1229. typesym :
  1230. begin
  1231. case ttypesym(sym).restype.def.deftype of
  1232. recorddef :
  1233. st:=trecorddef(ttypesym(sym).restype.def).symtable;
  1234. objectdef :
  1235. st:=tobjectdef(ttypesym(sym).restype.def).symtable;
  1236. end;
  1237. end;
  1238. typedconstsym :
  1239. begin
  1240. case ttypedconstsym(sym).typedconsttype.def.deftype of
  1241. recorddef :
  1242. st:=trecorddef(ttypedconstsym(sym).typedconsttype.def).symtable;
  1243. objectdef :
  1244. st:=tobjectdef(ttypedconstsym(sym).typedconsttype.def).symtable;
  1245. end;
  1246. end;
  1247. end;
  1248. end;
  1249. { now walk all recordsymtables }
  1250. while assigned(st) and (s<>'') do
  1251. begin
  1252. { load next field in base }
  1253. i:=pos('.',s);
  1254. if i=0 then
  1255. i:=255;
  1256. base:=Copy(s,1,i-1);
  1257. delete(s,1,i);
  1258. if st.symtabletype=objectsymtable then
  1259. sym:=search_class_member(tobjectdef(st.defowner),base)
  1260. else
  1261. sym:=tsym(st.search(base));
  1262. if not assigned(sym) then
  1263. begin
  1264. GetRecordOffsetSize:=false;
  1265. exit;
  1266. end;
  1267. st:=nil;
  1268. case sym.typ of
  1269. varsym :
  1270. begin
  1271. inc(Offset,tvarsym(sym).fieldoffset);
  1272. Size:=tvarsym(sym).getsize;
  1273. case tvarsym(sym).vartype.def.deftype of
  1274. arraydef :
  1275. begin
  1276. { for arrays try to get the element size, take care of
  1277. multiple indexes }
  1278. harrdef:=tarraydef(tvarsym(sym).vartype.def);
  1279. while assigned(harrdef.elementtype.def) and
  1280. (harrdef.elementtype.def.deftype=arraydef) do
  1281. harrdef:=tarraydef(harrdef.elementtype.def);
  1282. size:=harrdef.elesize;
  1283. end;
  1284. recorddef :
  1285. st:=trecorddef(tvarsym(sym).vartype.def).symtable;
  1286. objectdef :
  1287. st:=tobjectdef(tvarsym(sym).vartype.def).symtable;
  1288. end;
  1289. end;
  1290. end;
  1291. end;
  1292. GetRecordOffsetSize:=(s='');
  1293. end;
  1294. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  1295. var
  1296. sym : tsym;
  1297. srsymtable : tsymtable;
  1298. hs : string;
  1299. Begin
  1300. hl:=nil;
  1301. SearchLabel:=false;
  1302. { Check for pascal labels, which are case insensetive }
  1303. hs:=upper(s);
  1304. asmsearchsym(hs,sym,srsymtable);
  1305. if sym=nil then
  1306. exit;
  1307. case sym.typ of
  1308. labelsym :
  1309. begin
  1310. hl:=tlabelsym(sym).lab;
  1311. if emit then
  1312. tlabelsym(sym).defined:=true
  1313. else
  1314. tlabelsym(sym).used:=true;
  1315. SearchLabel:=true;
  1316. exit;
  1317. end;
  1318. end;
  1319. end;
  1320. {*************************************************************************}
  1321. { Instruction Generation Utilities }
  1322. {*************************************************************************}
  1323. Procedure ConcatString(p : TAAsmoutput;s:string);
  1324. {*********************************************************************}
  1325. { PROCEDURE ConcatString(s:string); }
  1326. { Description: This routine adds the character chain pointed to in }
  1327. { s to the instruction linked list. }
  1328. {*********************************************************************}
  1329. Var
  1330. pc: PChar;
  1331. Begin
  1332. getmem(pc,length(s)+1);
  1333. p.concat(Tai_string.Create_length_pchar(strpcopy(pc,s),length(s)));
  1334. end;
  1335. Procedure ConcatPasString(p : TAAsmoutput;s:string);
  1336. {*********************************************************************}
  1337. { PROCEDURE ConcatPasString(s:string); }
  1338. { Description: This routine adds the character chain pointed to in }
  1339. { s to the instruction linked list, contrary to ConcatString it }
  1340. { uses a pascal style string, so it conserves null characters. }
  1341. {*********************************************************************}
  1342. Begin
  1343. p.concat(Tai_string.Create(s));
  1344. end;
  1345. Procedure ConcatDirect(p : TAAsmoutput;s:string);
  1346. {*********************************************************************}
  1347. { PROCEDURE ConcatDirect(s:string) }
  1348. { Description: This routine output the string directly to the asm }
  1349. { output, it is only sed when writing special labels in AT&T mode, }
  1350. { and should not be used without due consideration, since it may }
  1351. { cause problems. }
  1352. {*********************************************************************}
  1353. Var
  1354. pc: PChar;
  1355. Begin
  1356. getmem(pc,length(s)+1);
  1357. p.concat(Tai_direct.Create(strpcopy(pc,s)));
  1358. end;
  1359. Procedure ConcatConstant(p: TAAsmoutput; value: longint; maxvalue: longint);
  1360. {*********************************************************************}
  1361. { PROCEDURE ConcatConstant(value: longint; maxvalue: longint); }
  1362. { Description: This routine adds the value constant to the current }
  1363. { instruction linked list. }
  1364. { maxvalue -> indicates the size of the data to initialize: }
  1365. { $ff -> create a byte node. }
  1366. { $ffff -> create a word node. }
  1367. { $ffffffff -> create a dword node. }
  1368. {*********************************************************************}
  1369. Begin
  1370. if (maxvalue <> longint($ffffffff)) and (value > maxvalue) then
  1371. Begin
  1372. Message(asmr_e_constant_out_of_bounds);
  1373. { assuming a value of maxvalue }
  1374. value:=maxvalue;
  1375. end;
  1376. if maxvalue = $ff then
  1377. p.concat(Tai_const.Create_8bit(byte(value)))
  1378. else
  1379. if maxvalue = $ffff then
  1380. p.concat(Tai_const.Create_16bit(word(value)))
  1381. else
  1382. if maxvalue = longint($ffffffff) then
  1383. p.concat(Tai_const.Create_32bit(longint(value)));
  1384. end;
  1385. Procedure ConcatConstSymbol(p : TAAsmoutput;const sym:string;l:longint);
  1386. begin
  1387. p.concat(Tai_const_symbol.Createname_offset(sym,l));
  1388. end;
  1389. Procedure ConcatRealConstant(p : TAAsmoutput;value: bestreal; real_typ : tfloattype);
  1390. {***********************************************************************}
  1391. { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1392. { Description: This routine adds the value constant to the current }
  1393. { instruction linked list. }
  1394. { real_typ -> indicates the type of the real data to initialize: }
  1395. { s32real -> create a single node. }
  1396. { s64real -> create a double node. }
  1397. { s80real -> create an extended node. }
  1398. { s64bit -> create a comp node. }
  1399. { f32bit -> create a fixed node. (not used normally) }
  1400. {***********************************************************************}
  1401. Begin
  1402. case real_typ of
  1403. s32real : p.concat(Tai_real_32bit.Create(value));
  1404. s64real : p.concat(Tai_real_64bit.Create(value));
  1405. s80real : p.concat(Tai_real_80bit.Create(value));
  1406. s64comp : p.concat(Tai_comp_64bit.Create(value));
  1407. end;
  1408. end;
  1409. Procedure ConcatLabel(p: TAAsmoutput;var l : tasmlabel);
  1410. {*********************************************************************}
  1411. { PROCEDURE ConcatLabel }
  1412. { Description: This routine either emits a label or a labeled }
  1413. { instruction to the linked list of instructions. }
  1414. {*********************************************************************}
  1415. begin
  1416. p.concat(Tai_label.Create(l));
  1417. end;
  1418. procedure ConcatAlign(p:TAAsmoutput;l:longint);
  1419. {*********************************************************************}
  1420. { PROCEDURE ConcatPublic }
  1421. { Description: This routine emits an global definition to the }
  1422. { linked list of instructions.(used by AT&T styled asm) }
  1423. {*********************************************************************}
  1424. begin
  1425. p.concat(Tai_align.Create(l));
  1426. end;
  1427. procedure ConcatPublic(p:TAAsmoutput;const s : string);
  1428. {*********************************************************************}
  1429. { PROCEDURE ConcatPublic }
  1430. { Description: This routine emits an global definition to the }
  1431. { linked list of instructions.(used by AT&T styled asm) }
  1432. {*********************************************************************}
  1433. begin
  1434. p.concat(Tai_symbol.Createname_global(s,0));
  1435. end;
  1436. procedure ConcatLocal(p:TAAsmoutput;const s : string);
  1437. {*********************************************************************}
  1438. { PROCEDURE ConcatLocal }
  1439. { Description: This routine emits an local definition to the }
  1440. { linked list of instructions. }
  1441. {*********************************************************************}
  1442. begin
  1443. p.concat(Tai_symbol.Createname(s,0));
  1444. end;
  1445. Procedure ConcatGlobalBss(const s : string;size : longint);
  1446. {*********************************************************************}
  1447. { PROCEDURE ConcatGlobalBss }
  1448. { Description: This routine emits an global datablock to the }
  1449. { linked list of instructions. }
  1450. {*********************************************************************}
  1451. begin
  1452. bssSegment.concat(Tai_datablock.Create_global(s,size));
  1453. end;
  1454. Procedure ConcatLocalBss(const s : string;size : longint);
  1455. {*********************************************************************}
  1456. { PROCEDURE ConcatLocalBss }
  1457. { Description: This routine emits a local datablcok to the }
  1458. { linked list of instructions. }
  1459. {*********************************************************************}
  1460. begin
  1461. bssSegment.concat(Tai_datablock.Create(s,size));
  1462. end;
  1463. end.
  1464. {
  1465. $Log$
  1466. Revision 1.77 2003-11-12 16:05:39 florian
  1467. * assembler readers OOPed
  1468. + typed currency constants
  1469. + typed 128 bit float constants if the CPU supports it
  1470. Revision 1.76 2003/10/30 19:59:00 peter
  1471. * support scalefactor for opr_local
  1472. * support reference with opr_local set, fixes tw2631
  1473. Revision 1.75 2003/10/29 16:47:18 peter
  1474. * fix field offset in reference
  1475. Revision 1.74 2003/10/29 15:40:20 peter
  1476. * support indexing and offset retrieval for locals
  1477. Revision 1.73 2003/10/28 15:36:01 peter
  1478. * absolute to object field supported, fixes tb0458
  1479. Revision 1.72 2003/10/24 17:39:03 peter
  1480. * more intel parser updates
  1481. Revision 1.71 2003/10/23 17:19:11 peter
  1482. * SearchType returns also the size
  1483. Revision 1.70 2003/10/08 19:39:58 peter
  1484. * allow access to parent locals when the currnet localst has no
  1485. varsyms
  1486. Revision 1.69 2003/10/01 20:34:49 peter
  1487. * procinfo unit contains tprocinfo
  1488. * cginfo renamed to cgbase
  1489. * moved cgmessage to verbose
  1490. * fixed ppc and sparc compiles
  1491. Revision 1.68 2003/09/25 14:57:36 peter
  1492. * fix check for unreachable locals
  1493. Revision 1.67 2003/09/23 17:56:06 peter
  1494. * locals and paras are allocated in the code generation
  1495. * tvarsym.localloc contains the location of para/local when
  1496. generating code for the current procedure
  1497. Revision 1.66 2003/09/16 16:17:01 peter
  1498. * varspez in calls to push_addr_param
  1499. Revision 1.65 2003/09/03 15:55:01 peter
  1500. * NEWRA branch merged
  1501. Revision 1.64.2.1 2003/08/27 19:55:54 peter
  1502. * first tregister patch
  1503. Revision 1.64 2003/06/13 21:19:31 peter
  1504. * current_procdef removed, use current_procinfo.procdef instead
  1505. Revision 1.63 2003/06/06 14:43:29 peter
  1506. * absolutesym support
  1507. Revision 1.62 2003/05/30 23:57:08 peter
  1508. * more sparc cleanup
  1509. * accumulator removed, splitted in function_return_reg (called) and
  1510. function_result_reg (caller)
  1511. Revision 1.61 2003/05/25 08:55:49 peter
  1512. * load result using hidden parameter
  1513. Revision 1.60 2003/05/15 18:58:53 peter
  1514. * removed selfpointer_offset, vmtpointer_offset
  1515. * tvarsym.adjusted_address
  1516. * address in localsymtable is now in the real direction
  1517. * removed some obsolete globals
  1518. Revision 1.59 2003/05/12 17:22:00 jonas
  1519. * fixed (last?) remaining -tvarsym(X).address to
  1520. tg.direction*tvarsym(X).address...
  1521. Revision 1.58 2003/04/27 11:21:34 peter
  1522. * aktprocdef renamed to current_procinfo.procdef
  1523. * procinfo renamed to current_procinfo
  1524. * procinfo will now be stored in current_module so it can be
  1525. cleaned up properly
  1526. * gen_main_procsym changed to create_main_proc and release_main_proc
  1527. to also generate a tprocinfo structure
  1528. * fixed unit implicit initfinal
  1529. Revision 1.57 2003/04/27 07:29:51 peter
  1530. * current_procinfo.procdef cleanup, current_procinfo.procdef is now always nil when parsing
  1531. a new procdef declaration
  1532. * aktprocsym removed
  1533. * lexlevel removed, use symtable.symtablelevel instead
  1534. * implicit init/final code uses the normal genentry/genexit
  1535. * funcret state checking updated for new funcret handling
  1536. Revision 1.56 2003/04/25 20:59:34 peter
  1537. * removed funcretn,funcretsym, function result is now in varsym
  1538. and aliases for result and function name are added using absolutesym
  1539. * vs_hidden parameter for funcret passed in parameter
  1540. * vs_hidden fixes
  1541. * writenode changed to printnode and released from extdebug
  1542. * -vp option added to generate a tree.log with the nodetree
  1543. * nicer printnode for statements, callnode
  1544. Revision 1.55 2003/04/06 21:11:23 olle
  1545. * changed newasmsymbol to newasmsymboldata for data symbols
  1546. Revision 1.54 2003/03/28 19:16:57 peter
  1547. * generic constructor working for i386
  1548. * remove fixed self register
  1549. * esi added as address register for i386
  1550. Revision 1.53 2003/02/19 22:00:14 daniel
  1551. * Code generator converted to new register notation
  1552. - Horribily outdated todo.txt removed
  1553. Revision 1.52 2003/01/08 18:43:56 daniel
  1554. * Tregister changed into a record
  1555. Revision 1.51 2002/12/14 15:02:03 carl
  1556. * maxoperands -> max_operands (for portability in rautils.pas)
  1557. * fix some range-check errors with loadconst
  1558. + add ncgadd unit to m68k
  1559. * some bugfix of a_param_reg with LOC_CREFERENCE
  1560. Revision 1.50 2002/11/25 17:43:23 peter
  1561. * splitted defbase in defutil,symutil,defcmp
  1562. * merged isconvertable and is_equal into compare_defs(_ext)
  1563. * made operator search faster by walking the list only once
  1564. Revision 1.49 2002/11/22 22:48:10 carl
  1565. * memory optimization with tconstsym (1.5%)
  1566. Revision 1.48 2002/11/18 17:31:59 peter
  1567. * pass proccalloption to ret_in_xxx and push_xxx functions
  1568. Revision 1.47 2002/11/15 16:29:31 peter
  1569. * made tasmsymbol.refs private (merged)
  1570. Revision 1.46 2002/09/03 16:26:27 daniel
  1571. * Make Tprocdef.defs protected
  1572. Revision 1.45 2002/08/25 19:25:20 peter
  1573. * sym.insert_in_data removed
  1574. * symtable.insertvardata/insertconstdata added
  1575. * removed insert_in_data call from symtable.insert, it needs to be
  1576. called separatly. This allows to deref the address calculation
  1577. * procedures now calculate the parast addresses after the procedure
  1578. directives are parsed. This fixes the cdecl parast problem
  1579. * push_addr_param has an extra argument that specifies if cdecl is used
  1580. or not
  1581. Revision 1.44 2002/08/17 09:23:41 florian
  1582. * first part of procinfo rewrite
  1583. Revision 1.43 2002/08/16 14:24:59 carl
  1584. * issameref() to test if two references are the same (then emit no opcodes)
  1585. + ret_in_reg to replace ret_in_acc
  1586. (fix some register allocation bugs at the same time)
  1587. + save_std_register now has an extra parameter which is the
  1588. usedinproc registers
  1589. Revision 1.42 2002/08/13 18:01:52 carl
  1590. * rename swatoperands to swapoperands
  1591. + m68k first compilable version (still needs a lot of testing):
  1592. assembler generator, system information , inline
  1593. assembler reader.
  1594. Revision 1.41 2002/08/12 15:08:40 carl
  1595. + stab register indexes for powerpc (moved from gdb to cpubase)
  1596. + tprocessor enumeration moved to cpuinfo
  1597. + linker in target_info is now a class
  1598. * many many updates for m68k (will soon start to compile)
  1599. - removed some ifdef or correct them for correct cpu
  1600. Revision 1.40 2002/08/11 14:32:27 peter
  1601. * renamed current_library to objectlibrary
  1602. Revision 1.39 2002/08/11 13:24:13 peter
  1603. * saving of asmsymbols in ppu supported
  1604. * asmsymbollist global is removed and moved into a new class
  1605. tasmlibrarydata that will hold the info of a .a file which
  1606. corresponds with a single module. Added librarydata to tmodule
  1607. to keep the library info stored for the module. In the future the
  1608. objectfiles will also be stored to the tasmlibrarydata class
  1609. * all getlabel/newasmsymbol and friends are moved to the new class
  1610. Revision 1.38 2002/07/20 11:57:57 florian
  1611. * types.pas renamed to defbase.pas because D6 contains a types
  1612. unit so this would conflicts if D6 programms are compiled
  1613. + Willamette/SSE2 instructions to assembler added
  1614. Revision 1.37 2002/07/11 14:41:28 florian
  1615. * start of the new generic parameter handling
  1616. Revision 1.36 2002/07/01 18:46:25 peter
  1617. * internal linker
  1618. * reorganized aasm layer
  1619. Revision 1.35 2002/05/18 13:34:17 peter
  1620. * readded missing revisions
  1621. Revision 1.34 2002/05/16 19:46:44 carl
  1622. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1623. + try to fix temp allocation (still in ifdef)
  1624. + generic constructor calls
  1625. + start of tassembler / tmodulebase class cleanup
  1626. Revision 1.31 2002/05/12 16:53:10 peter
  1627. * moved entry and exitcode to ncgutil and cgobj
  1628. * foreach gets extra argument for passing local data to the
  1629. iterator function
  1630. * -CR checks also class typecasts at runtime by changing them
  1631. into as
  1632. * fixed compiler to cycle with the -CR option
  1633. * fixed stabs with elf writer, finally the global variables can
  1634. be watched
  1635. * removed a lot of routines from cga unit and replaced them by
  1636. calls to cgobj
  1637. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  1638. u32bit then the other is typecasted also to u32bit without giving
  1639. a rangecheck warning/error.
  1640. * fixed pascal calling method with reversing also the high tree in
  1641. the parast, detected by tcalcst3 test
  1642. Revision 1.30 2002/04/20 21:32:24 carl
  1643. + generic FPC_CHECKPOINTER
  1644. + first parameter offset in stack now portable
  1645. * rename some constants
  1646. + move some cpu stuff to other units
  1647. - remove unused constents
  1648. * fix stacksize for some targets
  1649. * fix generic size problems which depend now on EXTEND_SIZE constant
  1650. Revision 1.29 2002/04/15 19:02:35 carl
  1651. + target_info.size_of_pointer -> pointer_Size
  1652. Revision 1.28 2002/04/02 17:11:29 peter
  1653. * tlocation,treference update
  1654. * LOC_CONSTANT added for better constant handling
  1655. * secondadd splitted in multiple routines
  1656. * location_force_reg added for loading a location to a register
  1657. of a specified size
  1658. * secondassignment parses now first the right and then the left node
  1659. (this is compatible with Kylix). This saves a lot of push/pop especially
  1660. with string operations
  1661. * adapted some routines to use the new cg methods
  1662. Revision 1.27 2002/01/29 21:32:03 peter
  1663. * allow accessing locals in other lexlevel when the current assembler
  1664. routine doesn't have locals.
  1665. Revision 1.26 2002/01/24 18:25:50 peter
  1666. * implicit result variable generation for assembler routines
  1667. * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
  1668. }