rautils.pas 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667
  1. {
  2. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  3. This unit implements some support routines for assembler parsing
  4. independent of the processor
  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. Unit RAUtils;
  18. {$i fpcdefs.inc}
  19. Interface
  20. Uses
  21. cutils,cclasses,
  22. globtype,aasmbase,aasmtai,aasmdata,cpubase,cpuinfo,cgbase,cgutils,
  23. symconst,symbase,symtype,symdef,symsym,symcpu;
  24. Const
  25. RPNMax = 10; { I think you only need 4, but just to be safe }
  26. OpMax = 25;
  27. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  28. {---------------------------------------------------------------------
  29. Instruction management
  30. ---------------------------------------------------------------------}
  31. type
  32. TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
  33. OPR_REFERENCE,OPR_REGISTER,OPR_COND,OPR_REGSET,
  34. OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG,
  35. OPR_REGPAIR);
  36. TOprRec = record
  37. case typ:TOprType of
  38. OPR_NONE : ();
  39. {$ifdef AVR}
  40. OPR_CONSTANT : (val:word);
  41. {$else AVR}
  42. OPR_CONSTANT : (val:aint);
  43. {$endif AVR}
  44. OPR_SYMBOL : (symbol:tasmsymbol;symofs:aint;symseg:boolean;sym_farproc_entry:boolean);
  45. OPR_REFERENCE : (varsize:asizeint; constoffset: asizeint;ref_farproc_entry:boolean;ref:treference);
  46. OPR_LOCAL : (localvarsize, localconstoffset: asizeint;localsym:tabstractnormalvarsym;localsymofs:aint;localindexreg:tregister;localscale:byte;localgetoffset,localforceref:boolean);
  47. OPR_REGISTER : (reg:tregister);
  48. {$ifdef m68k}
  49. OPR_REGSET : (regsetdata,regsetaddr,regsetfpu : tcpuregisterset);
  50. OPR_REGPAIR : (reghi,reglo: tregister);
  51. {$endif m68k}
  52. {$ifdef powerpc}
  53. OPR_COND : (cond : tasmcond);
  54. {$endif powerpc}
  55. {$ifdef POWERPC64}
  56. OPR_COND : (cond : tasmcond);
  57. {$endif POWERPC64}
  58. {$ifdef arm}
  59. OPR_REGSET : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister; usermode: boolean);
  60. OPR_SHIFTEROP : (shifterop : tshifterop);
  61. OPR_COND : (cc : tasmcond);
  62. OPR_MODEFLAGS : (flags : tcpumodeflags);
  63. OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags);
  64. {$endif arm}
  65. {$ifdef aarch64}
  66. OPR_SHIFTEROP : (shifterop : tshifterop);
  67. OPR_COND : (cc : tasmcond);
  68. {$endif aarch64}
  69. end;
  70. TOperand = class
  71. opr : TOprRec;
  72. typesize : byte;
  73. hastype, { if the operand has typecasted variable }
  74. hasvar : boolean; { if the operand is loaded with a variable }
  75. size : TCGSize;
  76. constructor create;virtual;
  77. destructor destroy;override;
  78. Procedure SetSize(_size:longint;force:boolean);virtual;
  79. Procedure SetCorrectSize(opcode:tasmop);virtual;
  80. Function SetupResult:boolean;virtual;
  81. Function SetupSelf:boolean;
  82. Function SetupOldEBP:boolean;
  83. Function SetupVar(const s:string;GetOffset : boolean): Boolean;
  84. Function CheckOperand: boolean; virtual;
  85. Procedure InitRef;
  86. Procedure InitRefConvertLocal;
  87. protected
  88. Procedure InitRefError;
  89. end;
  90. TCOperand = class of TOperand;
  91. TInstruction = class
  92. operands : array[1..max_operands] of toperand;
  93. opcode : tasmop;
  94. condition : tasmcond;
  95. ops : byte;
  96. labeled : boolean;
  97. filepos : tfileposinfo;
  98. constructor create(optype : tcoperand);virtual;
  99. destructor destroy;override;
  100. { converts the instruction to an instruction how it's used by the assembler writer
  101. and concats it to the passed list. The newly created item is returned if the
  102. instruction was valid, otherwise nil is returned }
  103. function ConcatInstruction(p:TAsmList) : tai;virtual;
  104. end;
  105. {---------------------------------------------------------------------}
  106. { Expression parser types }
  107. {---------------------------------------------------------------------}
  108. TExprOperator = record
  109. ch: char; { operator }
  110. is_prefix: boolean; { was it a prefix, possible prefixes are +,- and not }
  111. end;
  112. {**********************************************************************}
  113. { The following operators are supported: }
  114. { '+' : addition }
  115. { '-' : subtraction }
  116. { '*' : multiplication }
  117. { '/' : modulo division }
  118. { '^' : exclusive or }
  119. { '<' : shift left }
  120. { '>' : shift right }
  121. { '&' : bitwise and }
  122. { '|' : bitwise or }
  123. { '~' : bitwise complement }
  124. { '%' : modulo division }
  125. { nnn: longint numbers }
  126. { ( and ) parenthesis }
  127. {**********************************************************************}
  128. TExprParse = class
  129. public
  130. Constructor create;
  131. Destructor Destroy;override;
  132. Function Evaluate(Expr: String): tcgint;
  133. Function Priority(_Operator: Char): aint;
  134. private
  135. RPNStack : Array[1..RPNMax] of tcgint; { Stack For RPN calculator }
  136. RPNTop : tcgint;
  137. OpStack : Array[1..OpMax] of TExprOperator; { Operator stack For conversion }
  138. OpTop : tcgint;
  139. Procedure RPNPush(Num: tcgint);
  140. Function RPNPop: tcgint;
  141. Procedure RPNCalc(const token: String; prefix: boolean);
  142. Procedure OpPush(_Operator: char; prefix: boolean);
  143. { In reality returns TExprOperaotr }
  144. Procedure OpPop(var _Operator:TExprOperator);
  145. end;
  146. { Evaluate an expression string to a tcgint }
  147. Function CalculateExpression(const expression: string): tcgint;
  148. {---------------------------------------------------------------------}
  149. { String routines }
  150. {---------------------------------------------------------------------}
  151. Function ParseVal(const S:String;base:byte):tcgint;
  152. Function PadZero(Var s: String; n: byte): Boolean;
  153. Function EscapeToPascal(const s:string): string;
  154. {---------------------------------------------------------------------
  155. Symbol helper routines
  156. ---------------------------------------------------------------------}
  157. procedure AsmSearchSym(const s:string;var srsym:tsym;var srsymtable:TSymtable);
  158. Function GetRecordOffsetSize(s:string;Var Offset: tcgint;var Size:tcgint; var mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;
  159. Function SearchType(const hs:string;var size:tcgint): Boolean;
  160. Function SearchRecordType(const s:string): boolean;
  161. Function SearchIConstant(const s:string; var l:tcgint): boolean;
  162. Function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
  163. {---------------------------------------------------------------------
  164. Instruction generation routines
  165. ---------------------------------------------------------------------}
  166. Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);
  167. Procedure ConcatConstant(p : TAsmList;value: tcgint; constsize:byte);
  168. Procedure ConcatConstSymbol(p : TAsmList;const sym:string;symtyp:tasmsymtype;l:tcgint);
  169. Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);
  170. Procedure ConcatString(p : TAsmList;s:string);
  171. procedure ConcatAlign(p:TAsmList;l:tcgint);
  172. Procedure ConcatPublic(p:TAsmList;const s : string);
  173. Procedure ConcatLocal(p:TAsmList;const s : string);
  174. Implementation
  175. uses
  176. SysUtils,
  177. defutil,systems,verbose,globals,
  178. symtable,paramgr,
  179. aasmcpu,
  180. procinfo;
  181. {*************************************************************************
  182. TExprParse
  183. *************************************************************************}
  184. Constructor TExprParse.create;
  185. Begin
  186. end;
  187. Procedure TExprParse.RPNPush(Num : tcgint);
  188. { Add an operand to the top of the RPN stack }
  189. begin
  190. if RPNTop < RPNMax then
  191. begin
  192. Inc(RPNTop);
  193. RPNStack[RPNTop]:=Num;
  194. end
  195. else
  196. Message(asmr_e_expr_illegal);
  197. end;
  198. Function TExprParse.RPNPop : tcgint;
  199. { Get the operand at the top of the RPN stack }
  200. begin
  201. RPNPop:=0;
  202. if RPNTop > 0 then
  203. begin
  204. RPNPop:=RPNStack[RPNTop];
  205. Dec(RPNTop);
  206. end
  207. else
  208. Message(asmr_e_expr_illegal);
  209. end;
  210. Procedure TExprParse.RPNCalc(const Token : String; prefix:boolean); { RPN Calculator }
  211. Var
  212. Temp : tcgint;
  213. n1,n2 : tcgint;
  214. LocalError : Integer;
  215. begin
  216. { Handle operators }
  217. if (Length(Token) = 1) and (Token[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then
  218. Case Token[1] of
  219. '+' :
  220. Begin
  221. if not prefix then
  222. RPNPush(RPNPop + RPNPop);
  223. end;
  224. '-' :
  225. Begin
  226. if prefix then
  227. RPNPush(-(RPNPop))
  228. else
  229. begin
  230. n1:=RPNPop;
  231. n2:=RPNPop;
  232. RPNPush(n2 - n1);
  233. end;
  234. end;
  235. '*' : RPNPush(RPNPop * RPNPop);
  236. '&' :
  237. begin
  238. n1:=RPNPop;
  239. n2:=RPNPop;
  240. RPNPush(n2 and n1);
  241. end;
  242. '|' :
  243. begin
  244. n1:=RPNPop;
  245. n2:=RPNPop;
  246. RPNPush(n2 or n1);
  247. end;
  248. '~' : RPNPush(NOT RPNPop);
  249. '<' :
  250. begin
  251. n1:=RPNPop;
  252. n2:=RPNPop;
  253. RPNPush(n2 SHL n1);
  254. end;
  255. '>' :
  256. begin
  257. n1:=RPNPop;
  258. n2:=RPNPop;
  259. RPNPush(n2 SHR n1);
  260. end;
  261. '%' :
  262. begin
  263. Temp:=RPNPop;
  264. if Temp <> 0 then
  265. RPNPush(RPNPop mod Temp)
  266. else
  267. begin
  268. Message(asmr_e_expr_zero_divide);
  269. { push 1 for error recovery }
  270. RPNPush(1);
  271. end;
  272. end;
  273. '^' : RPNPush(RPNPop XOR RPNPop);
  274. '/' :
  275. begin
  276. Temp:=RPNPop;
  277. if Temp <> 0 then
  278. RPNPush(RPNPop div Temp)
  279. else
  280. begin
  281. Message(asmr_e_expr_zero_divide);
  282. { push 1 for error recovery }
  283. RPNPush(1);
  284. end;
  285. end;
  286. end
  287. else
  288. begin
  289. { Convert String to number and add to stack }
  290. Val(Token, Temp, LocalError);
  291. if LocalError = 0 then
  292. RPNPush(Temp)
  293. else
  294. begin
  295. Message(asmr_e_expr_illegal);
  296. { push 1 for error recovery }
  297. RPNPush(1);
  298. end;
  299. end;
  300. end;
  301. Procedure TExprParse.OpPush(_Operator : char;prefix: boolean);
  302. { Add an operator onto top of the stack }
  303. begin
  304. if OpTop < OpMax then
  305. begin
  306. Inc(OpTop);
  307. OpStack[OpTop].ch:=_Operator;
  308. OpStack[OpTop].is_prefix:=prefix;
  309. end
  310. else
  311. Message(asmr_e_expr_illegal);
  312. end;
  313. Procedure TExprParse.OpPop(var _Operator:TExprOperator);
  314. { Get operator at the top of the stack }
  315. begin
  316. if OpTop > 0 then
  317. begin
  318. _Operator:=OpStack[OpTop];
  319. Dec(OpTop);
  320. end
  321. else
  322. Message(asmr_e_expr_illegal);
  323. end;
  324. Function TExprParse.Priority(_Operator : Char) : aint;
  325. { Return priority of operator }
  326. { The greater the priority, the higher the precedence }
  327. begin
  328. Priority:=0;
  329. Case _Operator OF
  330. '(' :
  331. Priority:=0;
  332. '|','^','~' : // the lowest priority: OR, XOR, NOT
  333. Priority:=0;
  334. '&' : // bigger priority: AND
  335. Priority:=1;
  336. '+', '-' : // bigger priority: +, -
  337. Priority:=2;
  338. '*', '/','%','<','>' : // the highest priority: *, /, MOD, SHL, SHR
  339. Priority:=3;
  340. else
  341. Message(asmr_e_expr_illegal);
  342. end;
  343. end;
  344. Function TExprParse.Evaluate(Expr : String):tcgint;
  345. Var
  346. I : longint;
  347. Token : String;
  348. opr : TExprOperator;
  349. begin
  350. Evaluate:=0;
  351. { Reset stacks }
  352. OpTop :=0;
  353. RPNTop:=0;
  354. Token :='';
  355. { nothing to do ? }
  356. if Expr='' then
  357. exit;
  358. For I:=1 to Length(Expr) DO
  359. begin
  360. if Expr[I] in ['0'..'9'] then
  361. begin { Build multi-digit numbers }
  362. Token:=Token + Expr[I];
  363. if I = Length(Expr) then { Send last one to calculator }
  364. RPNCalc(Token,false);
  365. end
  366. else
  367. if Expr[I] in ['+', '-', '*', '/', '(', ')','^','&','|','%','~','<','>'] then
  368. begin
  369. if Token <> '' then
  370. begin { Send last built number to calc. }
  371. RPNCalc(Token,false);
  372. Token:='';
  373. end;
  374. Case Expr[I] OF
  375. '(' : OpPush('(',false);
  376. ')' : begin
  377. While (OpTop>0) and (OpStack[OpTop].ch <> '(') DO
  378. Begin
  379. OpPop(opr);
  380. RPNCalc(opr.ch,opr.is_prefix);
  381. end;
  382. OpPop(opr); { Pop off and ignore the '(' }
  383. end;
  384. '+','-','~' : Begin
  385. { workaround for -2147483648 }
  386. if (expr[I]='-') and (expr[i+1] in ['0'..'9']) then
  387. begin
  388. token:='-';
  389. expr[i]:='+';
  390. end;
  391. { if start of expression then surely a prefix }
  392. { or if previous char was also an operator }
  393. if (I = 1) or (not (Expr[I-1] in ['0'..'9',')'])) then
  394. OpPush(Expr[I],true)
  395. else
  396. Begin
  397. { Evaluate all higher priority operators }
  398. While (OpTop > 0) AND (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  399. Begin
  400. OpPop(opr);
  401. RPNCalc(opr.ch,opr.is_prefix);
  402. end;
  403. OpPush(Expr[I],false);
  404. End;
  405. end;
  406. '*', '/',
  407. '^','|','&',
  408. '%','<','>' : begin
  409. While (OpTop > 0) and (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO
  410. Begin
  411. OpPop(opr);
  412. RPNCalc(opr.ch,opr.is_prefix);
  413. end;
  414. OpPush(Expr[I],false);
  415. end;
  416. end; { Case }
  417. end
  418. else
  419. Message(asmr_e_expr_illegal); { Handle bad input error }
  420. end;
  421. { Pop off the remaining operators }
  422. While OpTop > 0 do
  423. Begin
  424. OpPop(opr);
  425. RPNCalc(opr.ch,opr.is_prefix);
  426. end;
  427. { The result is stored on the top of the stack }
  428. Evaluate:=RPNPop;
  429. end;
  430. Destructor TExprParse.Destroy;
  431. Begin
  432. end;
  433. Function CalculateExpression(const expression: string): tcgint;
  434. var
  435. expr: TExprParse;
  436. Begin
  437. expr:=TExprParse.create;
  438. CalculateExpression:=expr.Evaluate(expression);
  439. expr.Free;
  440. end;
  441. {*************************************************************************}
  442. { String conversions/utils }
  443. {*************************************************************************}
  444. Function EscapeToPascal(const s:string): string;
  445. { converts a C styled string - which contains escape }
  446. { characters to a pascal style string. }
  447. var
  448. i,len : asizeint;
  449. hs : string;
  450. temp : string;
  451. c : char;
  452. Begin
  453. hs:='';
  454. len:=0;
  455. i:=0;
  456. while (i<length(s)) and (len<255) do
  457. begin
  458. Inc(i);
  459. if (s[i]='\') and (i<length(s)) then
  460. Begin
  461. inc(i);
  462. case s[i] of
  463. '\' :
  464. c:='\';
  465. 'b':
  466. c:=#8;
  467. 'f':
  468. c:=#12;
  469. 'n':
  470. c:=#10;
  471. 'r':
  472. c:=#13;
  473. 't':
  474. c:=#9;
  475. '"':
  476. c:='"';
  477. '0'..'7':
  478. Begin
  479. temp:=s[i];
  480. temp:=temp+s[i+1];
  481. temp:=temp+s[i+2];
  482. inc(i,2);
  483. c:=chr(ParseVal(temp,8));
  484. end;
  485. 'x':
  486. Begin
  487. temp:=s[i+1];
  488. temp:=temp+s[i+2];
  489. inc(i,2);
  490. c:=chr(ParseVal(temp,16));
  491. end;
  492. else
  493. Begin
  494. Message1(asmr_e_escape_seq_ignored,s[i]);
  495. c:=s[i];
  496. end;
  497. end;
  498. end
  499. else
  500. c:=s[i];
  501. inc(len);
  502. hs[len]:=c;
  503. end;
  504. hs[0]:=chr(len);
  505. EscapeToPascal:=hs;
  506. end;
  507. Function ParseVal(const S:String;base:byte):tcgint;
  508. { Converts a decimal string to tcgint }
  509. var
  510. code : integer;
  511. errmsg : word;
  512. prefix : string[2];
  513. Begin
  514. case base of
  515. 2 :
  516. begin
  517. errmsg:=asmr_e_error_converting_binary;
  518. prefix:='%';
  519. end;
  520. 8 :
  521. begin
  522. errmsg:=asmr_e_error_converting_octal;
  523. prefix:='&';
  524. end;
  525. 10 :
  526. begin
  527. errmsg:=asmr_e_error_converting_decimal;
  528. prefix:='';
  529. end;
  530. 16 :
  531. begin
  532. errmsg:=asmr_e_error_converting_hexadecimal;
  533. prefix:='$';
  534. end;
  535. else
  536. internalerror(200501202);
  537. end;
  538. val(prefix+s,result,code);
  539. if code<>0 then
  540. begin
  541. val(prefix+s,result,code);
  542. if code<>0 then
  543. begin
  544. Message1(errmsg,s);
  545. result:=0;
  546. end;
  547. end;
  548. end;
  549. Function PadZero(Var s: String; n: byte): Boolean;
  550. Begin
  551. PadZero:=TRUE;
  552. { Do some error checking first }
  553. if Length(s) = n then
  554. exit
  555. else
  556. if Length(s) > n then
  557. Begin
  558. PadZero:=FALSE;
  559. delete(s,n+1,length(s));
  560. exit;
  561. end
  562. else
  563. PadZero:=TRUE;
  564. { Fill it up with the specified character }
  565. fillchar(s[length(s)+1],n-1,#0);
  566. s[0]:=chr(n);
  567. end;
  568. {****************************************************************************
  569. TOperand
  570. ****************************************************************************}
  571. constructor TOperand.Create;
  572. begin
  573. size:=OS_NO;
  574. hastype:=false;
  575. hasvar:=false;
  576. FillChar(Opr,sizeof(Opr),0);
  577. end;
  578. destructor TOperand.destroy;
  579. begin
  580. end;
  581. Procedure TOperand.SetSize(_size:longint;force:boolean);
  582. begin
  583. if force or
  584. ((size = OS_NO) and (_size<=16)) then
  585. Begin
  586. case _size of
  587. 1 : size:=OS_8;
  588. 2 : size:=OS_16{ could be S_IS};
  589. 4 : size:=OS_32{ could be S_IL or S_FS};
  590. 8 : size:=OS_64{ could be S_D or S_FL};
  591. 10 : size:=OS_F80;
  592. 16 : size:=OS_128;
  593. end;
  594. end;
  595. end;
  596. Procedure TOperand.SetCorrectSize(opcode:tasmop);
  597. begin
  598. end;
  599. function TOperand.SetupResult:boolean;
  600. begin
  601. SetupResult:=false;
  602. { replace by correct offset. }
  603. with current_procinfo.procdef do
  604. if (not is_void(returndef)) then
  605. begin
  606. if (m_tp7 in current_settings.modeswitches) and
  607. not (df_generic in defoptions) and
  608. (not paramanager.ret_in_param(returndef,current_procinfo.procdef)) then
  609. begin
  610. message(asmr_e_cannot_use_RESULT_here);
  611. exit;
  612. end;
  613. SetupResult:=setupvar('result',false)
  614. end
  615. else
  616. message(asmr_e_void_function);
  617. end;
  618. Function TOperand.SetupSelf:boolean;
  619. Begin
  620. SetupSelf:=false;
  621. if assigned(current_structdef) then
  622. SetupSelf:=setupvar('self',false)
  623. else
  624. Message(asmr_e_cannot_use_SELF_outside_a_method);
  625. end;
  626. Function TOperand.SetupOldEBP:boolean;
  627. Begin
  628. SetupOldEBP:=false;
  629. if current_procinfo.procdef.parast.symtablelevel>normal_function_level then
  630. SetupOldEBP:=setupvar('parentframe',false)
  631. else
  632. Message(asmr_e_cannot_use_OLDEBP_outside_nested_procedure);
  633. end;
  634. Function TOperand.SetupVar(const s:string;GetOffset : boolean): Boolean;
  635. function symtable_has_localvarsyms(st:TSymtable):boolean;
  636. var
  637. sym : tsym;
  638. i : longint;
  639. begin
  640. result:=false;
  641. for i:=0 to st.SymList.Count-1 do
  642. begin
  643. sym:=tsym(st.SymList[i]);
  644. if sym.typ=localvarsym then
  645. begin
  646. result:=true;
  647. exit;
  648. end;
  649. end;
  650. end;
  651. procedure setconst(l:aint);
  652. begin
  653. { We return the address of the field, just like Delphi/TP }
  654. case opr.typ of
  655. OPR_NONE :
  656. begin
  657. opr.typ:=OPR_CONSTANT;
  658. opr.val:=l;
  659. end;
  660. OPR_CONSTANT :
  661. inc(opr.val,l);
  662. OPR_REFERENCE :
  663. inc(opr.ref.offset,l);
  664. OPR_LOCAL :
  665. inc(opr.localsymofs,l);
  666. else
  667. Message(asmr_e_invalid_operand_type);
  668. end;
  669. end;
  670. procedure setvarsize(sym: tabstractvarsym);
  671. var
  672. harrdef: tarraydef;
  673. l: asizeint;
  674. begin
  675. case sym.vardef.typ of
  676. orddef,
  677. enumdef,
  678. pointerdef,
  679. procvardef,
  680. floatdef :
  681. SetSize(sym.getsize,false);
  682. arraydef :
  683. begin
  684. { for arrays try to get the element size, take care of
  685. multiple indexes }
  686. harrdef:=tarraydef(sym.vardef);
  687. { calc array size }
  688. if is_special_array(harrdef) then
  689. l := -1
  690. else
  691. l := harrdef.size;
  692. case opr.typ of
  693. OPR_REFERENCE: opr.varsize := l;
  694. OPR_LOCAL: opr.localvarsize := l;
  695. end;
  696. while assigned(harrdef.elementdef) and
  697. (harrdef.elementdef.typ=arraydef) do
  698. harrdef:=tarraydef(harrdef.elementdef);
  699. if not is_packed_array(harrdef) then
  700. SetSize(harrdef.elesize,false)
  701. else
  702. if (harrdef.elepackedbitsize mod 8) = 0 then
  703. SetSize(harrdef.elepackedbitsize div 8,false);
  704. end;
  705. recorddef:
  706. case opr.typ of
  707. OPR_REFERENCE: opr.varsize := sym.getsize;
  708. OPR_LOCAL: opr.localvarsize := sym.getsize;
  709. end;
  710. end;
  711. end;
  712. { search and sets up the correct fields in the Instr record }
  713. { for the NON-constant identifier passed to the routine. }
  714. { if not found returns FALSE. }
  715. var
  716. sym : tsym;
  717. srsymtable : TSymtable;
  718. indexreg : tregister;
  719. plist : ppropaccesslistitem;
  720. Begin
  721. SetupVar:=false;
  722. asmsearchsym(s,sym,srsymtable);
  723. if sym = nil then
  724. exit;
  725. if sym.typ=absolutevarsym then
  726. begin
  727. case tabsolutevarsym(sym).abstyp of
  728. tovar:
  729. begin
  730. { Only support simple loads }
  731. plist:=tabsolutevarsym(sym).ref.firstsym;
  732. if assigned(plist) and
  733. (plist^.sltype=sl_load) then
  734. sym:=plist^.sym
  735. else
  736. begin
  737. Message(asmr_e_unsupported_symbol_type);
  738. exit;
  739. end;
  740. end;
  741. toaddr:
  742. begin
  743. initref;
  744. opr.ref.offset:=tabsolutevarsym(sym).addroffset;
  745. Result:=true;
  746. exit;
  747. end;
  748. else
  749. begin
  750. Message(asmr_e_unsupported_symbol_type);
  751. exit;
  752. end;
  753. end;
  754. end;
  755. case sym.typ of
  756. fieldvarsym :
  757. begin
  758. if not tabstractrecordsymtable(sym.owner).is_packed then
  759. setconst(tfieldvarsym(sym).fieldoffset)
  760. else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then
  761. setconst(tfieldvarsym(sym).fieldoffset div 8)
  762. else
  763. Message(asmr_e_packed_element);
  764. setvarsize(tabstractvarsym(sym));
  765. hasvar:=true;
  766. SetupVar:=true;
  767. end;
  768. staticvarsym,
  769. localvarsym,
  770. paravarsym :
  771. begin
  772. { we always assume in asm statements that }
  773. { that the variable is valid. }
  774. tabstractvarsym(sym).varstate:=vs_readwritten;
  775. inc(tabstractvarsym(sym).refs);
  776. { variable can't be placed in a register }
  777. tabstractvarsym(sym).varregable:=vr_none;
  778. { and anything may happen with its address }
  779. tabstractvarsym(sym).addr_taken:=true;
  780. case sym.typ of
  781. staticvarsym :
  782. begin
  783. initref;
  784. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(sym).mangledname,AT_DATA);
  785. end;
  786. paravarsym,
  787. localvarsym :
  788. begin
  789. if opr.typ=OPR_REFERENCE then
  790. begin
  791. indexreg:=opr.ref.base;
  792. if opr.ref.index<>NR_NO then
  793. begin
  794. if indexreg=NR_NO then
  795. indexreg:=opr.ref.index
  796. else
  797. Message(asmr_e_multiple_index);
  798. end;
  799. end
  800. else
  801. indexreg:=NR_NO;
  802. opr.typ:=OPR_LOCAL;
  803. if assigned(current_procinfo.parent) and
  804. not(po_inline in current_procinfo.procdef.procoptions) and
  805. (sym.owner<>current_procinfo.procdef.localst) and
  806. (sym.owner<>current_procinfo.procdef.parast) and
  807. (current_procinfo.procdef.localst.symtablelevel>normal_function_level) and
  808. symtable_has_localvarsyms(current_procinfo.procdef.localst) then
  809. message1(asmr_e_local_para_unreachable,s);
  810. opr.localsym:=tabstractnormalvarsym(sym);
  811. opr.localsymofs:=0;
  812. opr.localindexreg:=indexreg;
  813. opr.localscale:=0;
  814. opr.localgetoffset:=GetOffset;
  815. if paramanager.push_addr_param(tabstractvarsym(sym).varspez,tabstractvarsym(sym).vardef,current_procinfo.procdef.proccalloption) then
  816. SetSize(sizeof(pint),false);
  817. end;
  818. end;
  819. setvarsize(tabstractvarsym(sym));
  820. hasvar:=true;
  821. SetupVar:=true;
  822. Exit;
  823. end;
  824. constsym :
  825. begin
  826. if tconstsym(sym).consttyp=constord then
  827. begin
  828. setconst(tconstsym(sym).value.valueord.svalue);
  829. SetupVar:=true;
  830. Exit;
  831. end;
  832. end;
  833. typesym :
  834. begin
  835. if ttypesym(sym).typedef.typ in [recorddef,objectdef] then
  836. begin
  837. setconst(0);
  838. SetupVar:=TRUE;
  839. Exit;
  840. end;
  841. end;
  842. procsym :
  843. begin
  844. if Tprocsym(sym).ProcdefList.Count>1 then
  845. Message(asmr_w_calling_overload_func);
  846. case opr.typ of
  847. OPR_REFERENCE:
  848. begin
  849. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);
  850. {$ifdef i8086}
  851. opr.ref_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))
  852. and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);
  853. {$endif i8086}
  854. end;
  855. OPR_NONE:
  856. begin
  857. opr.typ:=OPR_SYMBOL;
  858. opr.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);
  859. {$ifdef i8086}
  860. opr.sym_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))
  861. and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);
  862. {$endif i8086}
  863. opr.symofs:=0;
  864. end;
  865. else
  866. Message(asmr_e_invalid_operand_type);
  867. end;
  868. hasvar:=true;
  869. SetupVar:=TRUE;
  870. Exit;
  871. end;
  872. {$ifdef i8086}
  873. labelsym :
  874. begin
  875. case opr.typ of
  876. OPR_REFERENCE:
  877. begin
  878. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tlabelsym(sym).mangledname,AT_FUNCTION);
  879. if opr.ref.segment=NR_NO then
  880. opr.ref.segment:=NR_CS;
  881. end;
  882. else
  883. begin
  884. Message(asmr_e_unsupported_symbol_type);
  885. exit;
  886. end;
  887. end;
  888. hasvar:=true;
  889. SetupVar:=TRUE;
  890. Exit;
  891. end
  892. {$endif i8086}
  893. else
  894. begin
  895. Message(asmr_e_unsupported_symbol_type);
  896. exit;
  897. end;
  898. end;
  899. end;
  900. procedure TOperand.InitRef;
  901. {*********************************************************************}
  902. { Description: This routine first check if the opcode is of }
  903. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  904. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  905. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  906. { to point to the default segment. }
  907. {*********************************************************************}
  908. var
  909. l : aint;
  910. hsymofs : aint;
  911. hsymbol : tasmsymbol;
  912. reg : tregister;
  913. hsym_farprocentry: Boolean;
  914. Begin
  915. case opr.typ of
  916. OPR_REFERENCE :
  917. exit;
  918. OPR_CONSTANT :
  919. begin
  920. l:=opr.val;
  921. opr.typ:=OPR_REFERENCE;
  922. Fillchar(opr.ref,sizeof(treference),0);
  923. opr.Ref.Offset:=l;
  924. opr.varsize:=0;
  925. opr.constoffset:=0;
  926. opr.ref_farproc_entry:=false;
  927. end;
  928. OPR_NONE :
  929. begin
  930. opr.typ:=OPR_REFERENCE;
  931. opr.varsize:=0;
  932. opr.constoffset:=0;
  933. opr.ref_farproc_entry:=false;
  934. Fillchar(opr.ref,sizeof(treference),0);
  935. end;
  936. OPR_REGISTER :
  937. begin
  938. reg:=opr.reg;
  939. opr.typ:=OPR_REFERENCE;
  940. opr.varsize:=0;
  941. opr.constoffset:=0;
  942. opr.ref_farproc_entry:=false;
  943. Fillchar(opr.ref,sizeof(treference),0);
  944. opr.Ref.base:=reg;
  945. end;
  946. OPR_SYMBOL :
  947. begin
  948. hsymbol:=opr.symbol;
  949. hsymofs:=opr.symofs;
  950. hsym_farprocentry:=opr.sym_farproc_entry;
  951. opr.typ:=OPR_REFERENCE;
  952. opr.varsize:=0;
  953. opr.constoffset:=0;
  954. Fillchar(opr.ref,sizeof(treference),0);
  955. opr.ref.symbol:=hsymbol;
  956. opr.ref.offset:=hsymofs;
  957. opr.ref_farproc_entry:=hsym_farprocentry;
  958. end;
  959. else
  960. InitRefError;
  961. end;
  962. end;
  963. procedure TOperand.InitRefConvertLocal;
  964. var
  965. localvarsize,localconstoffset: asizeint;
  966. localsym:tabstractnormalvarsym;
  967. localsymofs:aint;
  968. localindexreg:tregister;
  969. localscale:byte;
  970. begin
  971. if opr.typ=OPR_LOCAL then
  972. begin
  973. if AsmRegisterPara(opr.localsym) and
  974. not opr.localgetoffset then
  975. begin
  976. localvarsize:=opr.localvarsize;
  977. localconstoffset:=opr.localconstoffset;
  978. localsym:=opr.localsym;
  979. localsymofs:=opr.localsymofs;
  980. localindexreg:=opr.localindexreg;
  981. localscale:=opr.localscale;;
  982. opr.typ:=OPR_REFERENCE;
  983. hasvar:=false;
  984. Fillchar(opr.ref,sizeof(treference),0);
  985. opr.varsize:=localvarsize;
  986. opr.constoffset:=localconstoffset;
  987. opr.ref_farproc_entry:=false;
  988. opr.ref.base:=tparavarsym(localsym).paraloc[calleeside].Location^.register;
  989. opr.ref.offset:=localsymofs;
  990. opr.ref.index:=localindexreg;
  991. opr.ref.scalefactor:=localscale;
  992. end
  993. else
  994. InitRefError;
  995. end
  996. else
  997. InitRef;
  998. end;
  999. procedure TOperand.InitRefError;
  1000. begin
  1001. Message(asmr_e_invalid_operand_type);
  1002. { Recover }
  1003. opr.typ:=OPR_REFERENCE;
  1004. opr.varsize:=0;
  1005. opr.constoffset:=0;
  1006. opr.ref_farproc_entry:=false;
  1007. Fillchar(opr.ref,sizeof(treference),0);
  1008. end;
  1009. Function TOperand.CheckOperand: boolean;
  1010. {*********************************************************************}
  1011. { Description: This routine checks if the operand is of }
  1012. { valid, and returns false if it isn't. Does nothing by default. }
  1013. {*********************************************************************}
  1014. begin
  1015. result:=true;
  1016. end;
  1017. {****************************************************************************
  1018. TInstruction
  1019. ****************************************************************************}
  1020. constructor TInstruction.create(optype : tcoperand);
  1021. var
  1022. i : longint;
  1023. Begin
  1024. { these field are set to 0 anyways by the constructor helper (FK)
  1025. Opcode:=A_NONE;
  1026. Condition:=C_NONE;
  1027. Ops:=0;
  1028. }
  1029. filepos:=current_filepos;
  1030. for i:=1 to max_operands do
  1031. Operands[i]:=optype.create;
  1032. Labeled:=false;
  1033. end;
  1034. destructor TInstruction.destroy;
  1035. var
  1036. i : longint;
  1037. Begin
  1038. for i:=1 to max_operands do
  1039. Operands[i].free;
  1040. end;
  1041. function TInstruction.ConcatInstruction(p:TAsmList) : tai;
  1042. var
  1043. ai : taicpu;
  1044. i : longint;
  1045. begin
  1046. for i:=1 to Ops do
  1047. operands[i].CheckOperand;
  1048. ai:=taicpu.op_none(opcode);
  1049. ai.fileinfo:=filepos;
  1050. ai.Ops:=Ops;
  1051. ai.Allocate_oper(Ops);
  1052. for i:=1 to Ops do
  1053. with operands[i].opr do
  1054. begin
  1055. case typ of
  1056. OPR_CONSTANT :
  1057. ai.loadconst(i-1,val);
  1058. OPR_REGISTER:
  1059. ai.loadreg(i-1,reg);
  1060. OPR_SYMBOL:
  1061. ai.loadsymbol(i-1,symbol,symofs);
  1062. OPR_LOCAL :
  1063. ai.loadlocal(i-1,localsym,localsymofs,localindexreg,
  1064. localscale,localgetoffset,localforceref);
  1065. OPR_REFERENCE:
  1066. ai.loadref(i-1,ref);
  1067. {$ifdef m68k}
  1068. OPR_REGSET:
  1069. ai.loadregset(i-1,regsetdata,regsetaddr,regsetfpu);
  1070. OPR_REGPAIR:
  1071. ai.loadregpair(i-1,reghi,reglo);
  1072. {$endif}
  1073. {$ifdef ARM}
  1074. OPR_REGSET:
  1075. ai.loadregset(i-1,regtype,subreg,regset,usermode);
  1076. OPR_MODEFLAGS:
  1077. ai.loadmodeflags(i-1,flags);
  1078. OPR_SPECIALREG:
  1079. ai.loadspecialreg(i-1,specialreg,specialregflags);
  1080. {$endif ARM}
  1081. {$if defined(arm) or defined(aarch64)}
  1082. OPR_SHIFTEROP:
  1083. ai.loadshifterop(i-1,shifterop);
  1084. OPR_COND:
  1085. ai.loadconditioncode(i-1,cc);
  1086. {$endif arm or aarch64}
  1087. { ignore wrong operand }
  1088. OPR_NONE:
  1089. ;
  1090. else
  1091. internalerror(200501051);
  1092. end;
  1093. end;
  1094. ai.SetCondition(condition);
  1095. { Concat the opcode or give an error }
  1096. if assigned(ai) then
  1097. p.concat(ai)
  1098. else
  1099. Message(asmr_e_invalid_opcode_and_operand);
  1100. result:=ai;
  1101. end;
  1102. {****************************************************************************
  1103. Symbol table helper routines
  1104. ****************************************************************************}
  1105. procedure AsmSearchSym(const s:string;var srsym:tsym;var srsymtable:TSymtable);
  1106. var
  1107. i : integer;
  1108. begin
  1109. i:=pos('.',s);
  1110. { allow unit.identifier }
  1111. if i>0 then
  1112. begin
  1113. searchsym(Copy(s,1,i-1),srsym,srsymtable);
  1114. if assigned(srsym) then
  1115. begin
  1116. if (srsym.typ=unitsym) and
  1117. (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and
  1118. srsym.owner.iscurrentunit then
  1119. searchsym_in_module(tunitsym(srsym).module,Copy(s,i+1,255),srsym,srsymtable)
  1120. else
  1121. begin
  1122. srsym:=nil;
  1123. srsymtable:=nil;
  1124. end;
  1125. end;
  1126. end
  1127. else
  1128. searchsym(s,srsym,srsymtable);
  1129. end;
  1130. Function SearchType(const hs:string;var size:tcgint): Boolean;
  1131. var
  1132. srsym : tsym;
  1133. srsymtable : TSymtable;
  1134. begin
  1135. result:=false;
  1136. size:=0;
  1137. asmsearchsym(hs,srsym,srsymtable);
  1138. if assigned(srsym) and
  1139. (srsym.typ=typesym) then
  1140. begin
  1141. size:=ttypesym(srsym).typedef.size;
  1142. result:=true;
  1143. end;
  1144. end;
  1145. Function SearchRecordType(const s:string): boolean;
  1146. var
  1147. srsym : tsym;
  1148. srsymtable : TSymtable;
  1149. Begin
  1150. SearchRecordType:=false;
  1151. { Check the constants in symtable }
  1152. asmsearchsym(s,srsym,srsymtable);
  1153. if srsym <> nil then
  1154. Begin
  1155. case srsym.typ of
  1156. typesym :
  1157. begin
  1158. if ttypesym(srsym).typedef.typ in [recorddef,objectdef] then
  1159. begin
  1160. SearchRecordType:=true;
  1161. exit;
  1162. end;
  1163. end;
  1164. fieldvarsym :
  1165. begin
  1166. if (tfieldvarsym(srsym).vardef.typ in [recorddef,objectdef]) then
  1167. begin
  1168. SearchRecordType:=true;
  1169. exit;
  1170. end;
  1171. end;
  1172. end;
  1173. end;
  1174. end;
  1175. Function SearchIConstant(const s:string; var l:tcgint): boolean;
  1176. {**********************************************************************}
  1177. { Description: Searches for a CONSTANT of name s in either the local }
  1178. { symbol list, then in the global symbol list, and returns the value }
  1179. { of that constant in l. Returns TRUE if successfull, if not found, }
  1180. { or if the constant is not of correct type, then returns FALSE }
  1181. { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  1182. { respectively. }
  1183. {**********************************************************************}
  1184. var
  1185. srsym : tsym;
  1186. srsymtable : TSymtable;
  1187. Begin
  1188. SearchIConstant:=false;
  1189. { check for TRUE or FALSE reserved words first }
  1190. if s = 'TRUE' then
  1191. Begin
  1192. SearchIConstant:=TRUE;
  1193. l:=1;
  1194. exit;
  1195. end;
  1196. if s = 'FALSE' then
  1197. Begin
  1198. SearchIConstant:=TRUE;
  1199. l:=0;
  1200. exit;
  1201. end;
  1202. { Check the constants in symtable }
  1203. asmsearchsym(s,srsym,srsymtable);
  1204. if srsym <> nil then
  1205. Begin
  1206. case srsym.typ of
  1207. constsym :
  1208. begin
  1209. if tconstsym(srsym).consttyp=constord then
  1210. Begin
  1211. l:=tconstsym(srsym).value.valueord.svalue;
  1212. SearchIConstant:=TRUE;
  1213. exit;
  1214. end;
  1215. end;
  1216. enumsym:
  1217. Begin
  1218. l:=tenumsym(srsym).value;
  1219. SearchIConstant:=TRUE;
  1220. exit;
  1221. end;
  1222. end;
  1223. end;
  1224. end;
  1225. function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
  1226. begin
  1227. result:=
  1228. (po_assembler in current_procinfo.procdef.procoptions) and
  1229. (sym.typ=paravarsym) and
  1230. (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REGISTER);
  1231. end;
  1232. Function GetRecordOffsetSize(s:string;Var Offset: tcgint;var Size:tcgint; var mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;
  1233. { search and returns the offset and size of records/objects of the base }
  1234. { with field name setup in field. }
  1235. { returns FALSE if not found. }
  1236. { used when base is a variable or a typed constant name. }
  1237. var
  1238. st : TSymtable;
  1239. harrdef : tarraydef;
  1240. sym : tsym;
  1241. srsymtable : TSymtable;
  1242. i : longint;
  1243. base : string;
  1244. procdef: tprocdef;
  1245. Begin
  1246. GetRecordOffsetSize:=FALSE;
  1247. Offset:=0;
  1248. Size:=0;
  1249. mangledname:='';
  1250. hastypecast:=false;
  1251. i:=pos('.',s);
  1252. if i=0 then
  1253. i:=255;
  1254. base:=Copy(s,1,i-1);
  1255. delete(s,1,i);
  1256. if base='SELF' then
  1257. st:=current_structdef.symtable
  1258. else
  1259. begin
  1260. asmsearchsym(base,sym,srsymtable);
  1261. st:=nil;
  1262. { we can start with a var,type,typedconst }
  1263. if assigned(sym) then
  1264. case sym.typ of
  1265. staticvarsym,
  1266. localvarsym,
  1267. paravarsym :
  1268. st:=Tabstractvarsym(sym).vardef.GetSymtable(gs_record);
  1269. typesym :
  1270. st:=Ttypesym(sym).typedef.GetSymtable(gs_record);
  1271. end
  1272. else
  1273. s:='';
  1274. end;
  1275. { now walk all recordsymtables }
  1276. while assigned(st) and (s<>'') do
  1277. begin
  1278. { load next field in base }
  1279. i:=pos('.',s);
  1280. if i=0 then
  1281. i:=255;
  1282. base:=Copy(s,1,i-1);
  1283. delete(s,1,i);
  1284. sym:=search_struct_member(tabstractrecorddef(st.defowner),base);
  1285. if not assigned(sym) then
  1286. begin
  1287. GetRecordOffsetSize:=false;
  1288. exit;
  1289. end;
  1290. st:=nil;
  1291. case sym.typ of
  1292. fieldvarsym :
  1293. with Tfieldvarsym(sym) do
  1294. begin
  1295. if not tabstractrecordsymtable(sym.owner).is_packed then
  1296. inc(Offset,fieldoffset)
  1297. else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then
  1298. inc(Offset,fieldoffset div 8)
  1299. else
  1300. Message(asmr_e_packed_element);
  1301. size:=getsize;
  1302. case vardef.typ of
  1303. arraydef :
  1304. begin
  1305. { for arrays try to get the element size, take care of
  1306. multiple indexes }
  1307. harrdef:=tarraydef(vardef);
  1308. while assigned(harrdef.elementdef) and
  1309. (harrdef.elementdef.typ=arraydef) do
  1310. harrdef:=tarraydef(harrdef.elementdef);
  1311. if not is_packed_array(harrdef) then
  1312. size:=harrdef.elesize
  1313. else
  1314. begin
  1315. if (harrdef.elepackedbitsize mod 8) <> 0 then
  1316. Message(asmr_e_packed_element);
  1317. size := (harrdef.elepackedbitsize + 7) div 8;
  1318. end;
  1319. end;
  1320. recorddef :
  1321. st:=trecorddef(vardef).symtable;
  1322. objectdef :
  1323. st:=tobjectdef(vardef).symtable;
  1324. end;
  1325. end;
  1326. procsym:
  1327. begin
  1328. st:=nil;
  1329. if Tprocsym(sym).ProcdefList.Count>1 then
  1330. Message(asmr_w_calling_overload_func);
  1331. procdef:=tprocdef(tprocsym(sym).ProcdefList[0]);
  1332. if (not needvmtofs) then
  1333. begin
  1334. mangledname:=procdef.mangledname;
  1335. end
  1336. else
  1337. begin
  1338. { can only get the vmtoffset of virtual methods }
  1339. if not(po_virtualmethod in procdef.procoptions) or
  1340. is_objectpascal_helper(procdef.struct) then
  1341. Message1(asmr_e_no_vmtoffset_possible,FullTypeName(procdef,nil))
  1342. else
  1343. begin
  1344. { size = sizeof(target_system_pointer) }
  1345. size:=sizeof(pint);
  1346. offset:=tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)
  1347. end;
  1348. end;
  1349. { if something comes after the procsym, it's invalid assembler syntax }
  1350. GetRecordOffsetSize:=(s='');
  1351. exit;
  1352. end;
  1353. end;
  1354. end;
  1355. { Support Field.Type as typecasting }
  1356. if (st=nil) and (s<>'') then
  1357. begin
  1358. asmsearchsym(s,sym,srsymtable);
  1359. if assigned(sym) and (sym.typ=typesym) then
  1360. begin
  1361. size:=ttypesym(sym).typedef.size;
  1362. s:='';
  1363. hastypecast:=true;
  1364. end;
  1365. end;
  1366. GetRecordOffsetSize:=(s='');
  1367. end;
  1368. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  1369. var
  1370. sym : tsym;
  1371. srsymtable : TSymtable;
  1372. hs : string;
  1373. Begin
  1374. hl:=nil;
  1375. SearchLabel:=false;
  1376. { Check for pascal labels, which are case insensetive }
  1377. hs:=upper(s);
  1378. asmsearchsym(hs,sym,srsymtable);
  1379. if sym=nil then
  1380. exit;
  1381. case sym.typ of
  1382. labelsym :
  1383. begin
  1384. if symtablestack.top.symtablelevel<>srsymtable.symtablelevel then
  1385. begin
  1386. Tlabelsym(sym).nonlocal:=true;
  1387. if emit then
  1388. exclude(current_procinfo.procdef.procoptions,po_inline);
  1389. end;
  1390. if not(assigned(tlabelsym(sym).asmblocklabel)) then
  1391. if Tlabelsym(sym).nonlocal then
  1392. current_asmdata.getglobaljumplabel(tlabelsym(sym).asmblocklabel)
  1393. else
  1394. current_asmdata.getjumplabel(tlabelsym(sym).asmblocklabel);
  1395. hl:=tlabelsym(sym).asmblocklabel;
  1396. if emit then
  1397. begin
  1398. if tlabelsym(sym).defined then
  1399. Message(sym_e_label_already_defined);
  1400. tlabelsym(sym).defined:=true
  1401. end
  1402. else
  1403. tlabelsym(sym).used:=true;
  1404. SearchLabel:=true;
  1405. end;
  1406. end;
  1407. end;
  1408. {*************************************************************************}
  1409. { Instruction Generation Utilities }
  1410. {*************************************************************************}
  1411. Procedure ConcatString(p : TAsmList;s:string);
  1412. {*********************************************************************}
  1413. { PROCEDURE ConcatString(s:string); }
  1414. { Description: This routine adds the character chain pointed to in }
  1415. { s to the instruction linked list. }
  1416. {*********************************************************************}
  1417. Begin
  1418. p.concat(Tai_string.Create(s));
  1419. end;
  1420. Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);
  1421. {*********************************************************************}
  1422. { PROCEDURE ConcatConstant(value: aint; maxvalue: aint); }
  1423. { Description: This routine adds the value constant to the current }
  1424. { instruction linked list. }
  1425. { maxvalue -> indicates the size of the data to initialize: }
  1426. { $ff -> create a byte node. }
  1427. { $ffff -> create a word node. }
  1428. { $ffffffff -> create a dword node. }
  1429. {*********************************************************************}
  1430. var
  1431. rangelo,rangehi : int64;
  1432. Begin
  1433. case constsize of
  1434. 1 :
  1435. begin
  1436. p.concat(Tai_const.Create_8bit(byte(value)));
  1437. rangelo:=low(shortint);
  1438. rangehi:=high(byte);
  1439. end;
  1440. 2 :
  1441. begin
  1442. p.concat(Tai_const.Create_16bit(word(value)));
  1443. rangelo:=low(smallint);
  1444. rangehi:=high(word);
  1445. end;
  1446. 4 :
  1447. begin
  1448. p.concat(Tai_const.Create_32bit(longint(value)));
  1449. rangelo:=low(longint);
  1450. rangehi:=high(cardinal);
  1451. end;
  1452. 8 :
  1453. begin
  1454. p.concat(Tai_const.Create_64bit(int64(value)));
  1455. rangelo:=0;
  1456. rangehi:=0;
  1457. end;
  1458. else
  1459. internalerror(200405011);
  1460. end;
  1461. { check for out of bounds }
  1462. if (rangelo<>0) and
  1463. ((value>rangehi) or (value<rangelo)) then
  1464. Message(asmr_e_constant_out_of_bounds);
  1465. end;
  1466. Procedure ConcatConstSymbol(p : TAsmList;const sym:string;symtyp:tasmsymtype;l:tcgint);
  1467. begin
  1468. p.concat(Tai_const.Createname(sym,l));
  1469. end;
  1470. Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);
  1471. {***********************************************************************}
  1472. { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1473. { Description: This routine adds the value constant to the current }
  1474. { instruction linked list. }
  1475. { real_typ -> indicates the type of the real data to initialize: }
  1476. { s32real -> create a single node. }
  1477. { s64real -> create a double node. }
  1478. { s80real -> create an extended node. }
  1479. { s64bit -> create a comp node. }
  1480. { f32bit -> create a fixed node. (not used normally) }
  1481. {***********************************************************************}
  1482. Begin
  1483. case real_typ of
  1484. s32real : p.concat(tai_realconst.create_s32real(value));
  1485. s64real :
  1486. {$ifdef ARM}
  1487. if is_double_hilo_swapped then
  1488. p.concat(tai_realconst.create_s64real_hiloswapped(value))
  1489. else
  1490. {$endif ARM}
  1491. p.concat(tai_realconst.create_s64real(value));
  1492. s80real : p.concat(tai_realconst.create_s80real(value,s80floattype.size));
  1493. sc80real : p.concat(tai_realconst.create_s80real(value,sc80floattype.size));
  1494. s64comp : p.concat(tai_realconst.create_s64compreal(trunc(value)));
  1495. else
  1496. internalerror(2014050608);
  1497. end;
  1498. end;
  1499. Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);
  1500. {*********************************************************************}
  1501. { PROCEDURE ConcatLabel }
  1502. { Description: This routine either emits a label or a labeled }
  1503. { instruction to the linked list of instructions. }
  1504. {*********************************************************************}
  1505. begin
  1506. p.concat(Tai_label.Create(l));
  1507. end;
  1508. procedure ConcatAlign(p:TAsmList;l:tcgint);
  1509. {*********************************************************************}
  1510. { PROCEDURE ConcatPublic }
  1511. { Description: This routine emits an global definition to the }
  1512. { linked list of instructions.(used by AT&T styled asm) }
  1513. {*********************************************************************}
  1514. begin
  1515. p.concat(Tai_align.Create(l));
  1516. end;
  1517. procedure ConcatPublic(p:TAsmList;const s : string);
  1518. {*********************************************************************}
  1519. { PROCEDURE ConcatPublic }
  1520. { Description: This routine emits an global definition to the }
  1521. { linked list of instructions.(used by AT&T styled asm) }
  1522. {*********************************************************************}
  1523. begin
  1524. p.concat(Tai_symbol.Createname_global(s,AT_LABEL,0,voidcodepointertype));
  1525. end;
  1526. procedure ConcatLocal(p:TAsmList;const s : string);
  1527. {*********************************************************************}
  1528. { PROCEDURE ConcatLocal }
  1529. { Description: This routine emits an local definition to the }
  1530. { linked list of instructions. }
  1531. {*********************************************************************}
  1532. begin
  1533. p.concat(Tai_symbol.Createname(s,AT_LABEL,0,voidcodepointertype));
  1534. end;
  1535. end.