rautils.pas 55 KB

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