rautils.pas 58 KB

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