rautils.pas 58 KB

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