2
0

rautils.pas 58 KB

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