rautils.pas 58 KB

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