rautils.pas 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868
  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,ngenutil;
  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. { llvm can't catch symbol references from inline assembler blocks }
  1280. if assigned(srsym) then
  1281. begin
  1282. case srsym.typ of
  1283. staticvarsym:
  1284. cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(srsym.mangledname,AT_DATA),tstaticvarsym(srsym).vardef,true);
  1285. procsym:
  1286. begin
  1287. { if it's a pure assembler routine, the definition of the symbol will also
  1288. be in assembler and it can't be removed by the compiler (and if we mark
  1289. it as used anyway, clang will get into trouble) }
  1290. if not(po_assembler in tprocdef(tprocsym(srsym).ProcdefList[0]).procoptions) then
  1291. cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(tprocdef(tprocsym(srsym).ProcdefList[0]).mangledname,AT_FUNCTION),tprocdef(tprocsym(srsym).ProcdefList[0]),true);
  1292. end;
  1293. end;
  1294. end;
  1295. end;
  1296. Function SearchType(const hs:string;out size:tcgint): Boolean;
  1297. var
  1298. srsym : tsym;
  1299. srsymtable : TSymtable;
  1300. begin
  1301. result:=false;
  1302. size:=0;
  1303. asmsearchsym(hs,srsym,srsymtable);
  1304. if assigned(srsym) and
  1305. (srsym.typ=typesym) then
  1306. begin
  1307. size:=ttypesym(srsym).typedef.size;
  1308. result:=true;
  1309. end;
  1310. end;
  1311. Function SearchRecordType(const s:string): boolean;
  1312. var
  1313. srsym : tsym;
  1314. srsymtable : TSymtable;
  1315. Begin
  1316. SearchRecordType:=false;
  1317. { Check the constants in symtable }
  1318. asmsearchsym(s,srsym,srsymtable);
  1319. if srsym <> nil then
  1320. Begin
  1321. case srsym.typ of
  1322. typesym :
  1323. begin
  1324. if ttypesym(srsym).typedef.typ in [recorddef,objectdef] then
  1325. begin
  1326. SearchRecordType:=true;
  1327. exit;
  1328. end;
  1329. end;
  1330. fieldvarsym :
  1331. begin
  1332. if (tfieldvarsym(srsym).vardef.typ in [recorddef,objectdef]) then
  1333. begin
  1334. SearchRecordType:=true;
  1335. exit;
  1336. end;
  1337. end;
  1338. end;
  1339. end;
  1340. end;
  1341. Function SearchIConstant(const s:string; var l:tcgint): boolean;
  1342. {**********************************************************************}
  1343. { Description: Searches for a CONSTANT of name s in either the local }
  1344. { symbol list, then in the global symbol list, and returns the value }
  1345. { of that constant in l. Returns TRUE if successfull, if not found, }
  1346. { or if the constant is not of correct type, then returns FALSE }
  1347. { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  1348. { respectively. }
  1349. {**********************************************************************}
  1350. var
  1351. srsym : tsym;
  1352. srsymtable : TSymtable;
  1353. Begin
  1354. SearchIConstant:=false;
  1355. { check for TRUE or FALSE reserved words first }
  1356. if s = 'TRUE' then
  1357. Begin
  1358. SearchIConstant:=TRUE;
  1359. l:=1;
  1360. exit;
  1361. end;
  1362. if s = 'FALSE' then
  1363. Begin
  1364. SearchIConstant:=TRUE;
  1365. l:=0;
  1366. exit;
  1367. end;
  1368. { Check the constants in symtable }
  1369. asmsearchsym(s,srsym,srsymtable);
  1370. if srsym <> nil then
  1371. Begin
  1372. case srsym.typ of
  1373. constsym :
  1374. begin
  1375. if tconstsym(srsym).consttyp=constord then
  1376. Begin
  1377. l:=tconstsym(srsym).value.valueord.svalue;
  1378. SearchIConstant:=TRUE;
  1379. exit;
  1380. end;
  1381. end;
  1382. enumsym:
  1383. Begin
  1384. l:=tenumsym(srsym).value;
  1385. SearchIConstant:=TRUE;
  1386. exit;
  1387. end;
  1388. end;
  1389. end;
  1390. end;
  1391. function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
  1392. begin
  1393. result:=
  1394. (po_assembler in current_procinfo.procdef.procoptions) and
  1395. (sym.typ=paravarsym) and
  1396. (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REGISTER);
  1397. end;
  1398. Function GetRecordOffsetSize(s:string;out Offset: tcgint;out Size:tcgint; out mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;
  1399. { search and returns the offset and size of records/objects of the base }
  1400. { with field name setup in field. }
  1401. { returns FALSE if not found. }
  1402. { used when base is a variable or a typed constant name. }
  1403. var
  1404. st : TSymtable;
  1405. harrdef : tarraydef;
  1406. sym : tsym;
  1407. srsymtable : TSymtable;
  1408. i : longint;
  1409. base : string;
  1410. procdef: tprocdef;
  1411. Begin
  1412. GetRecordOffsetSize:=FALSE;
  1413. Offset:=0;
  1414. Size:=0;
  1415. mangledname:='';
  1416. hastypecast:=false;
  1417. i:=pos('.',s);
  1418. if i=0 then
  1419. i:=255;
  1420. base:=Copy(s,1,i-1);
  1421. delete(s,1,i);
  1422. if base='SELF' then
  1423. st:=current_structdef.symtable
  1424. else
  1425. begin
  1426. asmsearchsym(base,sym,srsymtable);
  1427. { allow unitname.identifier }
  1428. if assigned(sym) and (sym.typ=unitsym) then
  1429. begin
  1430. i:=pos('.',s);
  1431. if i=0 then
  1432. i:=255;
  1433. base:=base+'.'+Copy(s,1,i-1);
  1434. delete(s,1,i);
  1435. asmsearchsym(base,sym,srsymtable);
  1436. end;
  1437. st:=nil;
  1438. { we can start with a var,type,typedconst }
  1439. if assigned(sym) then
  1440. case sym.typ of
  1441. staticvarsym,
  1442. localvarsym,
  1443. paravarsym :
  1444. st:=Tabstractvarsym(sym).vardef.GetSymtable(gs_record);
  1445. typesym :
  1446. st:=Ttypesym(sym).typedef.GetSymtable(gs_record);
  1447. end
  1448. else
  1449. s:='';
  1450. end;
  1451. { now walk all recordsymtables }
  1452. while assigned(st) and (s<>'') do
  1453. begin
  1454. { load next field in base }
  1455. i:=pos('.',s);
  1456. if i=0 then
  1457. i:=255;
  1458. base:=Copy(s,1,i-1);
  1459. delete(s,1,i);
  1460. sym:=search_struct_member(tabstractrecorddef(st.defowner),base);
  1461. if not assigned(sym) then
  1462. begin
  1463. GetRecordOffsetSize:=false;
  1464. exit;
  1465. end;
  1466. st:=nil;
  1467. case sym.typ of
  1468. fieldvarsym :
  1469. with Tfieldvarsym(sym) do
  1470. begin
  1471. if not tabstractrecordsymtable(sym.owner).is_packed then
  1472. inc(Offset,fieldoffset)
  1473. else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then
  1474. inc(Offset,fieldoffset div 8)
  1475. else
  1476. Message(asmr_e_packed_element);
  1477. size:=getsize;
  1478. case vardef.typ of
  1479. arraydef :
  1480. begin
  1481. { for arrays try to get the element size, take care of
  1482. multiple indexes }
  1483. harrdef:=tarraydef(vardef);
  1484. while assigned(harrdef.elementdef) and
  1485. (harrdef.elementdef.typ=arraydef) do
  1486. harrdef:=tarraydef(harrdef.elementdef);
  1487. if not is_packed_array(harrdef) then
  1488. size:=harrdef.elesize
  1489. else
  1490. begin
  1491. if (harrdef.elepackedbitsize mod 8) <> 0 then
  1492. Message(asmr_e_packed_element);
  1493. size := (harrdef.elepackedbitsize + 7) div 8;
  1494. end;
  1495. end;
  1496. recorddef :
  1497. st:=trecorddef(vardef).symtable;
  1498. objectdef :
  1499. st:=tobjectdef(vardef).symtable;
  1500. end;
  1501. end;
  1502. procsym:
  1503. begin
  1504. st:=nil;
  1505. if Tprocsym(sym).ProcdefList.Count>1 then
  1506. Message(asmr_w_calling_overload_func);
  1507. procdef:=tprocdef(tprocsym(sym).ProcdefList[0]);
  1508. if (not needvmtofs) then
  1509. begin
  1510. mangledname:=procdef.mangledname;
  1511. end
  1512. else
  1513. begin
  1514. { can only get the vmtoffset of virtual methods }
  1515. if not(po_virtualmethod in procdef.procoptions) or
  1516. is_objectpascal_helper(procdef.struct) then
  1517. Message1(asmr_e_no_vmtoffset_possible,FullTypeName(procdef,nil))
  1518. else
  1519. begin
  1520. { size = sizeof(target_system_pointer) }
  1521. size:=sizeof(pint);
  1522. offset:=tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)
  1523. end;
  1524. end;
  1525. { if something comes after the procsym, it's invalid assembler syntax }
  1526. GetRecordOffsetSize:=(s='');
  1527. exit;
  1528. end;
  1529. end;
  1530. end;
  1531. { Support Field.Type as typecasting }
  1532. if (st=nil) and (s<>'') then
  1533. begin
  1534. asmsearchsym(s,sym,srsymtable);
  1535. if assigned(sym) and (sym.typ=typesym) then
  1536. begin
  1537. size:=ttypesym(sym).typedef.size;
  1538. s:='';
  1539. hastypecast:=true;
  1540. end;
  1541. end;
  1542. GetRecordOffsetSize:=(s='');
  1543. end;
  1544. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  1545. var
  1546. sym : tsym;
  1547. srsymtable : TSymtable;
  1548. hs : string;
  1549. Begin
  1550. hl:=nil;
  1551. SearchLabel:=false;
  1552. { Check for pascal labels, which are case insensetive }
  1553. hs:=upper(s);
  1554. asmsearchsym(hs,sym,srsymtable);
  1555. if sym=nil then
  1556. exit;
  1557. case sym.typ of
  1558. labelsym :
  1559. begin
  1560. if symtablestack.top.symtablelevel<>srsymtable.symtablelevel then
  1561. begin
  1562. Tlabelsym(sym).nonlocal:=true;
  1563. if emit then
  1564. exclude(current_procinfo.procdef.procoptions,po_inline);
  1565. end;
  1566. if not(assigned(tlabelsym(sym).asmblocklabel)) then
  1567. if Tlabelsym(sym).nonlocal then
  1568. current_asmdata.getglobaljumplabel(tlabelsym(sym).asmblocklabel)
  1569. else
  1570. current_asmdata.getjumplabel(tlabelsym(sym).asmblocklabel);
  1571. hl:=tlabelsym(sym).asmblocklabel;
  1572. if emit then
  1573. begin
  1574. if tlabelsym(sym).defined then
  1575. Message(sym_e_label_already_defined);
  1576. tlabelsym(sym).defined:=true
  1577. end
  1578. else
  1579. tlabelsym(sym).used:=true;
  1580. SearchLabel:=true;
  1581. end;
  1582. end;
  1583. end;
  1584. {*************************************************************************}
  1585. { Instruction Generation Utilities }
  1586. {*************************************************************************}
  1587. Procedure ConcatString(p : TAsmList;s:string);
  1588. {*********************************************************************}
  1589. { PROCEDURE ConcatString(s:string); }
  1590. { Description: This routine adds the character chain pointed to in }
  1591. { s to the instruction linked list. }
  1592. {*********************************************************************}
  1593. Begin
  1594. p.concat(Tai_string.Create(s));
  1595. end;
  1596. Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);
  1597. {*********************************************************************}
  1598. { PROCEDURE ConcatConstant(value: aint; maxvalue: aint); }
  1599. { Description: This routine adds the value constant to the current }
  1600. { instruction linked list. }
  1601. { maxvalue -> indicates the size of the data to initialize: }
  1602. { $ff -> create a byte node. }
  1603. { $ffff -> create a word node. }
  1604. { $ffffffff -> create a dword node. }
  1605. {*********************************************************************}
  1606. var
  1607. rangelo,rangehi : int64;
  1608. Begin
  1609. case constsize of
  1610. 1 :
  1611. begin
  1612. p.concat(Tai_const.Create_8bit(byte(value)));
  1613. rangelo:=low(shortint);
  1614. rangehi:=high(byte);
  1615. end;
  1616. 2 :
  1617. begin
  1618. p.concat(Tai_const.Create_16bit(word(value)));
  1619. rangelo:=low(smallint);
  1620. rangehi:=high(word);
  1621. end;
  1622. 4 :
  1623. begin
  1624. p.concat(Tai_const.Create_32bit(longint(value)));
  1625. rangelo:=low(longint);
  1626. rangehi:=high(cardinal);
  1627. end;
  1628. 8 :
  1629. begin
  1630. p.concat(Tai_const.Create_64bit(int64(value)));
  1631. rangelo:=0;
  1632. rangehi:=0;
  1633. end;
  1634. else
  1635. internalerror(200405011);
  1636. end;
  1637. { check for out of bounds }
  1638. if (rangelo<>0) and
  1639. ((value>rangehi) or (value<rangelo)) then
  1640. Message(asmr_e_constant_out_of_bounds);
  1641. end;
  1642. Procedure ConcatConstSymbol(p : TAsmList;const sym:string;symtyp:tasmsymtype;l:tcgint;constsize:byte;isofs:boolean);
  1643. begin
  1644. {$ifdef i8086}
  1645. { 'DW xx' as well as 'DW OFFSET xx' are just near pointers }
  1646. if constsize=2 then
  1647. p.concat(Tai_const.Createname_near(sym,l))
  1648. else if constsize=4 then
  1649. begin
  1650. if isofs then
  1651. begin
  1652. { 'DD OFFSET xx' is a 32-bit offset; since we don't produce 32-bit
  1653. relocations yet, just do a 16-bit one and set the high word to 0 }
  1654. p.concat(Tai_const.Createname_near(sym,l));
  1655. p.concat(Tai_const.Create_16bit(0));
  1656. end
  1657. else
  1658. { 'DD xx' is a far pointer }
  1659. p.concat(Tai_const.Createname_far(sym,l));
  1660. end
  1661. else
  1662. internalerror(2018020701);
  1663. {$else i8086}
  1664. p.concat(Tai_const.Createname(sym,l));
  1665. {$endif i8086}
  1666. end;
  1667. Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);
  1668. {***********************************************************************}
  1669. { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1670. { Description: This routine adds the value constant to the current }
  1671. { instruction linked list. }
  1672. { real_typ -> indicates the type of the real data to initialize: }
  1673. { s32real -> create a single node. }
  1674. { s64real -> create a double node. }
  1675. { s80real -> create an extended node. }
  1676. { s64bit -> create a comp node. }
  1677. { f32bit -> create a fixed node. (not used normally) }
  1678. {***********************************************************************}
  1679. Begin
  1680. case real_typ of
  1681. s32real : p.concat(tai_realconst.create_s32real(value));
  1682. s64real :
  1683. {$ifdef ARM}
  1684. if is_double_hilo_swapped then
  1685. p.concat(tai_realconst.create_s64real_hiloswapped(value))
  1686. else
  1687. {$endif ARM}
  1688. p.concat(tai_realconst.create_s64real(value));
  1689. s80real : p.concat(tai_realconst.create_s80real(value,s80floattype.size));
  1690. sc80real : p.concat(tai_realconst.create_s80real(value,sc80floattype.size));
  1691. s64comp : p.concat(tai_realconst.create_s64compreal(trunc(value)));
  1692. else
  1693. internalerror(2014050608);
  1694. end;
  1695. end;
  1696. Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);
  1697. {*********************************************************************}
  1698. { PROCEDURE ConcatLabel }
  1699. { Description: This routine either emits a label or a labeled }
  1700. { instruction to the linked list of instructions. }
  1701. {*********************************************************************}
  1702. begin
  1703. p.concat(Tai_label.Create(l));
  1704. end;
  1705. procedure ConcatAlign(p:TAsmList;l:tcgint);
  1706. {*********************************************************************}
  1707. { PROCEDURE ConcatPublic }
  1708. { Description: This routine emits an global definition to the }
  1709. { linked list of instructions.(used by AT&T styled asm) }
  1710. {*********************************************************************}
  1711. begin
  1712. p.concat(Tai_align.Create(l));
  1713. end;
  1714. procedure ConcatPublic(p:TAsmList;const s : string);
  1715. {*********************************************************************}
  1716. { PROCEDURE ConcatPublic }
  1717. { Description: This routine emits an global definition to the }
  1718. { linked list of instructions.(used by AT&T styled asm) }
  1719. {*********************************************************************}
  1720. begin
  1721. p.concat(Tai_symbol.Createname_global(s,AT_LABEL,0,voidcodepointertype));
  1722. end;
  1723. procedure ConcatLocal(p:TAsmList;const s : string);
  1724. {*********************************************************************}
  1725. { PROCEDURE ConcatLocal }
  1726. { Description: This routine emits an local definition to the }
  1727. { linked list of instructions. }
  1728. {*********************************************************************}
  1729. begin
  1730. p.concat(Tai_symbol.Createname(s,AT_LABEL,0,voidcodepointertype));
  1731. end;
  1732. end.