rautils.pas 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892
  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. else
  717. ;
  718. end;
  719. while assigned(harrdef.elementdef) and
  720. (harrdef.elementdef.typ=arraydef) do
  721. harrdef:=tarraydef(harrdef.elementdef);
  722. if not is_packed_array(harrdef) then
  723. SetSize(harrdef.elesize,false)
  724. else
  725. if (harrdef.elepackedbitsize mod 8) = 0 then
  726. SetSize(harrdef.elepackedbitsize div 8,false);
  727. end;
  728. recorddef:
  729. case opr.typ of
  730. OPR_REFERENCE: opr.varsize := sym.getsize;
  731. OPR_LOCAL: opr.localvarsize := sym.getsize;
  732. else
  733. ;
  734. end;
  735. else
  736. ;
  737. end;
  738. end;
  739. { search and sets up the correct fields in the Instr record }
  740. { for the NON-constant identifier passed to the routine. }
  741. { if not found returns FALSE. }
  742. var
  743. sym : tsym;
  744. srsymtable : TSymtable;
  745. {$ifdef x86}
  746. segreg,
  747. {$endif x86}
  748. indexreg : tregister;
  749. plist : ppropaccesslistitem;
  750. size_set_from_absolute : boolean = false;
  751. { offset fixup (in bytes), coming from an absolute declaration with an index
  752. (e.g. var tralala: word absolute moo[5]; ) }
  753. absoffset: asizeint=0;
  754. harrdef: tarraydef;
  755. tmpprocinfo: tprocinfo;
  756. Begin
  757. SetupVar:=false;
  758. asmsearchsym(s,sym,srsymtable);
  759. if sym = nil then
  760. exit;
  761. if sym.typ=absolutevarsym then
  762. begin
  763. case tabsolutevarsym(sym).abstyp of
  764. tovar:
  765. begin
  766. { Only support simple loads }
  767. plist:=tabsolutevarsym(sym).ref.firstsym;
  768. if assigned(plist) and
  769. (plist^.sltype=sl_load) then
  770. begin
  771. setvarsize(tabstractvarsym(sym));
  772. size_set_from_absolute:=true;
  773. sym:=plist^.sym;
  774. { resolve the chain of array indexes (if there are any) }
  775. harrdef:=nil;
  776. while assigned(plist^.next) do
  777. begin
  778. plist:=plist^.next;
  779. if (plist^.sltype=sl_vec) and (tabstractvarsym(sym).vardef.typ=arraydef) then
  780. begin
  781. if harrdef=nil then
  782. harrdef:=tarraydef(tabstractvarsym(sym).vardef)
  783. else if harrdef.elementdef.typ=arraydef then
  784. harrdef:=tarraydef(harrdef.elementdef)
  785. else
  786. begin
  787. Message(asmr_e_unsupported_symbol_type);
  788. exit;
  789. end;
  790. if is_special_array(harrdef) then
  791. begin
  792. Message(asmr_e_unsupported_symbol_type);
  793. exit;
  794. end;
  795. if not is_packed_array(harrdef) then
  796. Inc(absoffset,asizeint(Int64(plist^.value-harrdef.lowrange))*harrdef.elesize)
  797. else if (Int64(plist^.value-harrdef.lowrange)*harrdef.elepackedbitsize mod 8)=0 then
  798. Inc(absoffset,asizeint(Int64(plist^.value-harrdef.lowrange)*harrdef.elepackedbitsize div 8))
  799. else
  800. Message(asmr_e_packed_element);
  801. end
  802. else
  803. begin
  804. Message(asmr_e_unsupported_symbol_type);
  805. exit;
  806. end;
  807. end;
  808. end
  809. else
  810. begin
  811. Message(asmr_e_unsupported_symbol_type);
  812. exit;
  813. end;
  814. end;
  815. toaddr:
  816. begin
  817. initref;
  818. opr.ref.offset:=tabsolutevarsym(sym).addroffset;
  819. setvarsize(tabstractvarsym(sym));
  820. size_set_from_absolute:=true;
  821. hasvar:=true;
  822. Result:=true;
  823. exit;
  824. end;
  825. else
  826. begin
  827. Message(asmr_e_unsupported_symbol_type);
  828. exit;
  829. end;
  830. end;
  831. end;
  832. case sym.typ of
  833. fieldvarsym :
  834. begin
  835. if not tabstractrecordsymtable(sym.owner).is_packed then
  836. setconst(absoffset+tfieldvarsym(sym).fieldoffset)
  837. else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then
  838. setconst(absoffset+tfieldvarsym(sym).fieldoffset div 8)
  839. else
  840. Message(asmr_e_packed_element);
  841. if not size_set_from_absolute then
  842. setvarsize(tabstractvarsym(sym));
  843. hasvar:=true;
  844. SetupVar:=true;
  845. end;
  846. staticvarsym,
  847. localvarsym,
  848. paravarsym :
  849. begin
  850. { we always assume in asm statements that }
  851. { that the variable is valid. }
  852. tabstractvarsym(sym).varstate:=vs_readwritten;
  853. inc(tabstractvarsym(sym).refs);
  854. { variable can't be placed in a register }
  855. tabstractvarsym(sym).varregable:=vr_none;
  856. { and anything may happen with its address }
  857. tabstractvarsym(sym).addr_taken:=true;
  858. case sym.typ of
  859. staticvarsym :
  860. begin
  861. initref;
  862. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(sym).mangledname,AT_DATA);
  863. Inc(opr.ref.offset,absoffset);
  864. end;
  865. paravarsym,
  866. localvarsym :
  867. begin
  868. tmpprocinfo:=current_procinfo;
  869. while assigned(tmpprocinfo) do
  870. begin
  871. if (sym.owner=tmpprocinfo.procdef.localst) or
  872. (sym.owner=tmpprocinfo.procdef.parast) then
  873. begin
  874. tmpprocinfo.procdef.init_paraloc_info(calleeside);
  875. break;
  876. end;
  877. tmpprocinfo:=tmpprocinfo.parent;
  878. end;
  879. if opr.typ=OPR_REFERENCE then
  880. begin
  881. {$ifdef x86}
  882. segreg:=opr.ref.segment;
  883. {$endif x86}
  884. indexreg:=opr.ref.base;
  885. if opr.ref.index<>NR_NO then
  886. begin
  887. if indexreg=NR_NO then
  888. indexreg:=opr.ref.index
  889. else
  890. Message(asmr_e_multiple_index);
  891. end;
  892. end
  893. else
  894. begin
  895. {$ifdef x86}
  896. segreg:=NR_NO;
  897. {$endif x86}
  898. indexreg:=NR_NO;
  899. end;
  900. opr.typ:=OPR_LOCAL;
  901. if assigned(current_procinfo.parent) and
  902. not(po_inline in current_procinfo.procdef.procoptions) and
  903. (sym.owner<>current_procinfo.procdef.localst) and
  904. (sym.owner<>current_procinfo.procdef.parast) and
  905. (current_procinfo.procdef.localst.symtablelevel>normal_function_level) and
  906. symtable_has_localvarsyms(current_procinfo.procdef.localst) then
  907. message1(asmr_e_local_para_unreachable,s);
  908. opr.localsym:=tabstractnormalvarsym(sym);
  909. opr.localsymofs:=absoffset;
  910. {$ifdef x86}
  911. opr.localsegment:=segreg;
  912. {$endif x86}
  913. opr.localindexreg:=indexreg;
  914. opr.localscale:=0;
  915. opr.localgetoffset:=GetOffset;
  916. if paramanager.push_addr_param(tabstractvarsym(sym).varspez,tabstractvarsym(sym).vardef,current_procinfo.procdef.proccalloption) then
  917. SetSize(sizeof(pint),false);
  918. end;
  919. else
  920. ;
  921. end;
  922. if not size_set_from_absolute then
  923. setvarsize(tabstractvarsym(sym));
  924. hasvar:=true;
  925. SetupVar:=true;
  926. Exit;
  927. end;
  928. constsym :
  929. begin
  930. if tconstsym(sym).consttyp=constord then
  931. begin
  932. setconst(tconstsym(sym).value.valueord.svalue);
  933. SetupVar:=true;
  934. Exit;
  935. end;
  936. end;
  937. typesym :
  938. begin
  939. if ttypesym(sym).typedef.typ in [recorddef,objectdef] then
  940. begin
  941. setconst(0);
  942. SetupVar:=TRUE;
  943. Exit;
  944. end;
  945. end;
  946. procsym :
  947. begin
  948. if Tprocsym(sym).ProcdefList.Count>1 then
  949. Message(asmr_w_calling_overload_func);
  950. case opr.typ of
  951. OPR_REFERENCE:
  952. begin
  953. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);
  954. Inc(opr.ref.offset,absoffset);
  955. {$ifdef i8086}
  956. opr.ref_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))
  957. and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);
  958. {$endif i8086}
  959. end;
  960. OPR_NONE:
  961. begin
  962. opr.typ:=OPR_SYMBOL;
  963. opr.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);
  964. {$ifdef i8086}
  965. opr.sym_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))
  966. and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);
  967. {$endif i8086}
  968. opr.symofs:=absoffset;
  969. end;
  970. else
  971. Message(asmr_e_invalid_operand_type);
  972. end;
  973. hasproc:=true;
  974. hasvar:=true;
  975. SetupVar:=TRUE;
  976. Exit;
  977. end;
  978. {$ifdef i8086}
  979. labelsym :
  980. begin
  981. case opr.typ of
  982. OPR_REFERENCE:
  983. begin
  984. opr.ref.symbol:=current_asmdata.RefAsmSymbol(tlabelsym(sym).mangledname,AT_FUNCTION);
  985. Inc(opr.ref.offset,absoffset);
  986. if opr.ref.segment=NR_NO then
  987. opr.ref.segment:=NR_CS;
  988. end;
  989. else
  990. begin
  991. Message(asmr_e_unsupported_symbol_type);
  992. exit;
  993. end;
  994. end;
  995. haslabelref:=true;
  996. hasvar:=true;
  997. SetupVar:=TRUE;
  998. Exit;
  999. end
  1000. {$endif i8086}
  1001. else
  1002. begin
  1003. Message(asmr_e_unsupported_symbol_type);
  1004. exit;
  1005. end;
  1006. end;
  1007. end;
  1008. procedure TOperand.InitRef;
  1009. {*********************************************************************}
  1010. { Description: This routine first check if the opcode is of }
  1011. { type OPR_NONE, or OPR_REFERENCE , if not it gives out an error. }
  1012. { If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up }
  1013. { the operand type to OPR_REFERENCE, as well as setting up the ref }
  1014. { to point to the default segment. }
  1015. {*********************************************************************}
  1016. var
  1017. l : aint;
  1018. hsymofs : aint;
  1019. hsymbol : tasmsymbol;
  1020. reg : tregister;
  1021. hsym_farprocentry: Boolean;
  1022. Begin
  1023. case opr.typ of
  1024. OPR_REFERENCE :
  1025. exit;
  1026. OPR_CONSTANT :
  1027. begin
  1028. l:=opr.val;
  1029. opr.typ:=OPR_REFERENCE;
  1030. Fillchar(opr.ref,sizeof(treference),0);
  1031. opr.Ref.Offset:=l;
  1032. opr.varsize:=0;
  1033. opr.constoffset:=0;
  1034. opr.ref_farproc_entry:=false;
  1035. end;
  1036. OPR_NONE :
  1037. begin
  1038. opr.typ:=OPR_REFERENCE;
  1039. opr.varsize:=0;
  1040. opr.constoffset:=0;
  1041. opr.ref_farproc_entry:=false;
  1042. Fillchar(opr.ref,sizeof(treference),0);
  1043. end;
  1044. OPR_REGISTER :
  1045. begin
  1046. reg:=opr.reg;
  1047. opr.typ:=OPR_REFERENCE;
  1048. opr.varsize:=0;
  1049. opr.constoffset:=0;
  1050. opr.ref_farproc_entry:=false;
  1051. Fillchar(opr.ref,sizeof(treference),0);
  1052. opr.Ref.base:=reg;
  1053. end;
  1054. OPR_SYMBOL :
  1055. begin
  1056. hsymbol:=opr.symbol;
  1057. hsymofs:=opr.symofs;
  1058. hsym_farprocentry:=opr.sym_farproc_entry;
  1059. opr.typ:=OPR_REFERENCE;
  1060. opr.varsize:=0;
  1061. opr.constoffset:=0;
  1062. Fillchar(opr.ref,sizeof(treference),0);
  1063. opr.ref.symbol:=hsymbol;
  1064. opr.ref.offset:=hsymofs;
  1065. opr.ref_farproc_entry:=hsym_farprocentry;
  1066. end;
  1067. else
  1068. InitRefError;
  1069. end;
  1070. end;
  1071. procedure TOperand.InitRefConvertLocal;
  1072. var
  1073. localvarsize,localconstoffset: asizeint;
  1074. localsym:tabstractnormalvarsym;
  1075. localsymofs:aint;
  1076. {$ifdef x86}
  1077. localsegment,
  1078. {$endif x86}
  1079. localindexreg:tregister;
  1080. localscale:byte;
  1081. begin
  1082. if opr.typ=OPR_LOCAL then
  1083. begin
  1084. if AsmRegisterPara(opr.localsym) and
  1085. not opr.localgetoffset then
  1086. begin
  1087. localvarsize:=opr.localvarsize;
  1088. localconstoffset:=opr.localconstoffset;
  1089. localsym:=opr.localsym;
  1090. localsymofs:=opr.localsymofs;
  1091. {$ifdef x86}
  1092. localsegment:=opr.localsegment;
  1093. {$endif x86}
  1094. localindexreg:=opr.localindexreg;
  1095. localscale:=opr.localscale;;
  1096. opr.typ:=OPR_REFERENCE;
  1097. hasvar:=false;
  1098. Fillchar(opr.ref,sizeof(treference),0);
  1099. opr.varsize:=localvarsize;
  1100. opr.constoffset:=localconstoffset;
  1101. opr.ref_farproc_entry:=false;
  1102. opr.ref.base:=tparavarsym(localsym).paraloc[calleeside].Location^.register;
  1103. opr.ref.offset:=localsymofs;
  1104. {$ifdef x86}
  1105. opr.ref.segment:=localsegment;
  1106. {$endif x86}
  1107. opr.ref.index:=localindexreg;
  1108. opr.ref.scalefactor:=localscale;
  1109. end
  1110. else
  1111. InitRefError;
  1112. end
  1113. else
  1114. InitRef;
  1115. end;
  1116. procedure TOperand.InitRefError;
  1117. begin
  1118. Message(asmr_e_invalid_operand_type);
  1119. { Recover }
  1120. opr.typ:=OPR_REFERENCE;
  1121. opr.varsize:=0;
  1122. opr.constoffset:=0;
  1123. opr.ref_farproc_entry:=false;
  1124. Fillchar(opr.ref,sizeof(treference),0);
  1125. end;
  1126. Function TOperand.CheckOperand: boolean;
  1127. {*********************************************************************}
  1128. { Description: This routine checks if the operand is of }
  1129. { valid, and returns false if it isn't. Does nothing by default. }
  1130. {*********************************************************************}
  1131. begin
  1132. result:=true;
  1133. end;
  1134. {****************************************************************************
  1135. TInstruction
  1136. ****************************************************************************}
  1137. constructor TInstruction.create(optype : tcoperand);
  1138. var
  1139. i : longint;
  1140. Begin
  1141. { these field are set to 0 anyways by the constructor helper (FK)
  1142. Opcode:=A_NONE;
  1143. Condition:=C_NONE;
  1144. Ops:=0;
  1145. }
  1146. filepos:=current_filepos;
  1147. for i:=1 to max_operands do
  1148. Operands[i]:=optype.create;
  1149. Labeled:=false;
  1150. end;
  1151. destructor TInstruction.destroy;
  1152. var
  1153. i : longint;
  1154. Begin
  1155. for i:=1 to max_operands do
  1156. Operands[i].free;
  1157. end;
  1158. function TInstruction.ConcatInstruction(p:TAsmList) : tai;
  1159. var
  1160. ai : taicpu;
  1161. i : longint;
  1162. begin
  1163. for i:=1 to Ops do
  1164. operands[i].CheckOperand;
  1165. ai:=taicpu.op_none(opcode);
  1166. ai.fileinfo:=filepos;
  1167. ai.Ops:=Ops;
  1168. ai.Allocate_oper(Ops);
  1169. for i:=1 to Ops do
  1170. with operands[i].opr do
  1171. begin
  1172. case typ of
  1173. OPR_CONSTANT :
  1174. ai.loadconst(i-1,val);
  1175. OPR_REGISTER:
  1176. ai.loadreg(i-1,reg);
  1177. OPR_SYMBOL:
  1178. ai.loadsymbol(i-1,symbol,symofs);
  1179. OPR_LOCAL :
  1180. begin
  1181. ai.loadlocal(i-1,localsym,localsymofs,localindexreg,
  1182. localscale,localgetoffset,localforceref);
  1183. {$ifdef x86}
  1184. ai.oper[i-1]^.localoper^.localsegment:=localsegment;
  1185. {$endif x86}
  1186. end;
  1187. OPR_REFERENCE:
  1188. ai.loadref(i-1,ref);
  1189. {$ifdef m68k}
  1190. OPR_REGSET:
  1191. ai.loadregset(i-1,regsetdata,regsetaddr,regsetfpu);
  1192. OPR_REGPAIR:
  1193. ai.loadregpair(i-1,reghi,reglo);
  1194. {$endif}
  1195. {$ifdef ARM}
  1196. OPR_REGSET:
  1197. ai.loadregset(i-1,regtype,subreg,regset,usermode);
  1198. OPR_MODEFLAGS:
  1199. ai.loadmodeflags(i-1,flags);
  1200. OPR_SPECIALREG:
  1201. ai.loadspecialreg(i-1,specialreg,specialregflags);
  1202. {$endif ARM}
  1203. {$if defined(arm) or defined(aarch64)}
  1204. OPR_SHIFTEROP:
  1205. ai.loadshifterop(i-1,shifterop);
  1206. OPR_COND:
  1207. ai.loadconditioncode(i-1,cc);
  1208. {$endif arm or aarch64}
  1209. {$if defined(riscv32) or defined(riscv64)}
  1210. OPR_FENCEFLAGS:
  1211. ai.loadfenceflags(i-1,fenceflags);
  1212. {$endif riscv32 or riscv64}
  1213. { ignore wrong operand }
  1214. OPR_NONE:
  1215. ;
  1216. else
  1217. internalerror(200501051);
  1218. end;
  1219. end;
  1220. ai.SetCondition(condition);
  1221. { Concat the opcode or give an error }
  1222. if assigned(ai) then
  1223. p.concat(ai)
  1224. else
  1225. Message(asmr_e_invalid_opcode_and_operand);
  1226. result:=ai;
  1227. end;
  1228. {****************************************************************************
  1229. Symbol table helper routines
  1230. ****************************************************************************}
  1231. procedure AsmSearchSym(const s:string;out srsym:tsym;out srsymtable:TSymtable);
  1232. var
  1233. i : integer;
  1234. begin
  1235. i:=pos('.',s);
  1236. { allow unit.identifier }
  1237. if i>0 then
  1238. begin
  1239. searchsym(Copy(s,1,i-1),srsym,srsymtable);
  1240. if assigned(srsym) then
  1241. begin
  1242. if (srsym.typ=unitsym) and
  1243. (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and
  1244. srsym.owner.iscurrentunit then
  1245. searchsym_in_module(tunitsym(srsym).module,Copy(s,i+1,255),srsym,srsymtable)
  1246. else
  1247. begin
  1248. srsym:=nil;
  1249. srsymtable:=nil;
  1250. end;
  1251. end;
  1252. end
  1253. else
  1254. searchsym(s,srsym,srsymtable);
  1255. { in asm routines, the function result variable, that matches the function
  1256. name should be avoided, because:
  1257. 1) there's already a @Result directive (even in TP7) that can be used, if
  1258. you want to access the function result
  1259. 2) there's no other way to disambiguate between the function result variable
  1260. and the function's address (using asm syntax only)
  1261. This fixes code, such as:
  1262. function test1: word;
  1263. begin
  1264. asm
  1265. mov ax, offset test1
  1266. end;
  1267. end;
  1268. and makes it work in a consistent manner as this code:
  1269. procedure test2;
  1270. begin
  1271. asm
  1272. mov ax, offset test2
  1273. end;
  1274. end; }
  1275. if assigned(srsym) and
  1276. assigned(srsymtable) and
  1277. (srsym.typ=absolutevarsym) and
  1278. (vo_is_funcret in tabsolutevarsym(srsym).varoptions) and
  1279. (srsymtable.symtabletype=localsymtable) and
  1280. assigned(srsymtable.defowner) and
  1281. (srsymtable.defowner.typ=procdef) and
  1282. (tprocdef(srsymtable.defowner).procsym.name=tabsolutevarsym(srsym).Name) then
  1283. begin
  1284. srsym:=tprocdef(srsymtable.defowner).procsym;
  1285. srsymtable:=srsym.Owner;
  1286. end;
  1287. { llvm can't catch symbol references from inline assembler blocks }
  1288. if assigned(srsym) then
  1289. begin
  1290. case srsym.typ of
  1291. staticvarsym:
  1292. if not(vo_is_external in tstaticvarsym(srsym).varoptions) then
  1293. cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(srsym.mangledname,AT_DATA),tstaticvarsym(srsym).vardef,true);
  1294. procsym:
  1295. begin
  1296. { if it's a pure assembler routine, the definition of the symbol will also
  1297. be in assembler and it can't be removed by the compiler (and if we mark
  1298. it as used anyway, clang will get into trouble) }
  1299. if not(po_assembler in tprocdef(tprocsym(srsym).ProcdefList[0]).procoptions) and
  1300. not(po_external in tprocdef(tprocsym(srsym).ProcdefList[0]).procoptions) then
  1301. cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(tprocdef(tprocsym(srsym).ProcdefList[0]).mangledname,AT_FUNCTION),tprocdef(tprocsym(srsym).ProcdefList[0]),true);
  1302. end;
  1303. else
  1304. ;
  1305. end;
  1306. end;
  1307. end;
  1308. Function SearchType(const hs:string;out size:tcgint): Boolean;
  1309. var
  1310. srsym : tsym;
  1311. srsymtable : TSymtable;
  1312. begin
  1313. result:=false;
  1314. size:=0;
  1315. asmsearchsym(hs,srsym,srsymtable);
  1316. if assigned(srsym) and
  1317. (srsym.typ=typesym) then
  1318. begin
  1319. size:=ttypesym(srsym).typedef.size;
  1320. result:=true;
  1321. end;
  1322. end;
  1323. Function SearchRecordType(const s:string): boolean;
  1324. var
  1325. srsym : tsym;
  1326. srsymtable : TSymtable;
  1327. Begin
  1328. SearchRecordType:=false;
  1329. { Check the constants in symtable }
  1330. asmsearchsym(s,srsym,srsymtable);
  1331. if srsym <> nil then
  1332. Begin
  1333. case srsym.typ of
  1334. typesym :
  1335. begin
  1336. if ttypesym(srsym).typedef.typ in [recorddef,objectdef] then
  1337. begin
  1338. SearchRecordType:=true;
  1339. exit;
  1340. end;
  1341. end;
  1342. fieldvarsym :
  1343. begin
  1344. if (tfieldvarsym(srsym).vardef.typ in [recorddef,objectdef]) then
  1345. begin
  1346. SearchRecordType:=true;
  1347. exit;
  1348. end;
  1349. end;
  1350. else
  1351. ;
  1352. end;
  1353. end;
  1354. end;
  1355. Function SearchIConstant(const s:string; var l:tcgint): boolean;
  1356. {**********************************************************************}
  1357. { Description: Searches for a CONSTANT of name s in either the local }
  1358. { symbol list, then in the global symbol list, and returns the value }
  1359. { of that constant in l. Returns TRUE if successfull, if not found, }
  1360. { or if the constant is not of correct type, then returns FALSE }
  1361. { Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }
  1362. { respectively. }
  1363. {**********************************************************************}
  1364. var
  1365. srsym : tsym;
  1366. srsymtable : TSymtable;
  1367. Begin
  1368. SearchIConstant:=false;
  1369. { check for TRUE or FALSE reserved words first }
  1370. if s = 'TRUE' then
  1371. Begin
  1372. SearchIConstant:=TRUE;
  1373. l:=1;
  1374. exit;
  1375. end;
  1376. if s = 'FALSE' then
  1377. Begin
  1378. SearchIConstant:=TRUE;
  1379. l:=0;
  1380. exit;
  1381. end;
  1382. { Check the constants in symtable }
  1383. asmsearchsym(s,srsym,srsymtable);
  1384. if srsym <> nil then
  1385. Begin
  1386. case srsym.typ of
  1387. constsym :
  1388. begin
  1389. if tconstsym(srsym).consttyp=constord then
  1390. Begin
  1391. l:=tconstsym(srsym).value.valueord.svalue;
  1392. SearchIConstant:=TRUE;
  1393. exit;
  1394. end;
  1395. end;
  1396. enumsym:
  1397. Begin
  1398. l:=tenumsym(srsym).value;
  1399. SearchIConstant:=TRUE;
  1400. exit;
  1401. end;
  1402. else
  1403. ;
  1404. end;
  1405. end;
  1406. end;
  1407. function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;
  1408. begin
  1409. result:=
  1410. (po_assembler in current_procinfo.procdef.procoptions) and
  1411. (sym.typ=paravarsym) and
  1412. (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REGISTER);
  1413. end;
  1414. Function GetRecordOffsetSize(s:string;out Offset: tcgint;out Size:tcgint; out mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;
  1415. { search and returns the offset and size of records/objects of the base }
  1416. { with field name setup in field. }
  1417. { returns FALSE if not found. }
  1418. { used when base is a variable or a typed constant name. }
  1419. var
  1420. st : TSymtable;
  1421. harrdef : tarraydef;
  1422. sym : tsym;
  1423. srsymtable : TSymtable;
  1424. i : longint;
  1425. base : string;
  1426. procdef: tprocdef;
  1427. Begin
  1428. GetRecordOffsetSize:=FALSE;
  1429. Offset:=0;
  1430. Size:=0;
  1431. mangledname:='';
  1432. hastypecast:=false;
  1433. i:=pos('.',s);
  1434. if i=0 then
  1435. i:=255;
  1436. base:=Copy(s,1,i-1);
  1437. delete(s,1,i);
  1438. if base='SELF' then
  1439. st:=current_structdef.symtable
  1440. else
  1441. begin
  1442. asmsearchsym(base,sym,srsymtable);
  1443. { allow unitname.identifier }
  1444. if assigned(sym) and (sym.typ=unitsym) then
  1445. begin
  1446. i:=pos('.',s);
  1447. if i=0 then
  1448. i:=255;
  1449. base:=base+'.'+Copy(s,1,i-1);
  1450. delete(s,1,i);
  1451. asmsearchsym(base,sym,srsymtable);
  1452. end;
  1453. st:=nil;
  1454. { we can start with a var,type,typedconst }
  1455. if assigned(sym) then
  1456. case sym.typ of
  1457. staticvarsym,
  1458. localvarsym,
  1459. paravarsym :
  1460. st:=Tabstractvarsym(sym).vardef.GetSymtable(gs_record);
  1461. typesym :
  1462. st:=Ttypesym(sym).typedef.GetSymtable(gs_record);
  1463. else
  1464. ;
  1465. end
  1466. else
  1467. s:='';
  1468. end;
  1469. { now walk all recordsymtables }
  1470. while assigned(st) and (s<>'') do
  1471. begin
  1472. { load next field in base }
  1473. i:=pos('.',s);
  1474. if i=0 then
  1475. i:=255;
  1476. base:=Copy(s,1,i-1);
  1477. delete(s,1,i);
  1478. sym:=search_struct_member(tabstractrecorddef(st.defowner),base);
  1479. if not assigned(sym) then
  1480. begin
  1481. GetRecordOffsetSize:=false;
  1482. exit;
  1483. end;
  1484. st:=nil;
  1485. case sym.typ of
  1486. fieldvarsym :
  1487. with Tfieldvarsym(sym) do
  1488. begin
  1489. if not tabstractrecordsymtable(sym.owner).is_packed then
  1490. inc(Offset,fieldoffset)
  1491. else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then
  1492. inc(Offset,fieldoffset div 8)
  1493. else
  1494. Message(asmr_e_packed_element);
  1495. size:=getsize;
  1496. case vardef.typ of
  1497. arraydef :
  1498. begin
  1499. { for arrays try to get the element size, take care of
  1500. multiple indexes }
  1501. harrdef:=tarraydef(vardef);
  1502. while assigned(harrdef.elementdef) and
  1503. (harrdef.elementdef.typ=arraydef) do
  1504. harrdef:=tarraydef(harrdef.elementdef);
  1505. if not is_packed_array(harrdef) then
  1506. size:=harrdef.elesize
  1507. else
  1508. begin
  1509. if (harrdef.elepackedbitsize mod 8) <> 0 then
  1510. Message(asmr_e_packed_element);
  1511. size := (harrdef.elepackedbitsize + 7) div 8;
  1512. end;
  1513. end;
  1514. recorddef :
  1515. st:=trecorddef(vardef).symtable;
  1516. objectdef :
  1517. st:=tobjectdef(vardef).symtable;
  1518. else
  1519. ;
  1520. end;
  1521. end;
  1522. procsym:
  1523. begin
  1524. st:=nil;
  1525. if Tprocsym(sym).ProcdefList.Count>1 then
  1526. Message(asmr_w_calling_overload_func);
  1527. procdef:=tprocdef(tprocsym(sym).ProcdefList[0]);
  1528. if (not needvmtofs) then
  1529. begin
  1530. mangledname:=procdef.mangledname;
  1531. end
  1532. else
  1533. begin
  1534. { can only get the vmtoffset of virtual methods }
  1535. if not(po_virtualmethod in procdef.procoptions) or
  1536. is_objectpascal_helper(procdef.struct) then
  1537. Message1(asmr_e_no_vmtoffset_possible,FullTypeName(procdef,nil))
  1538. else
  1539. begin
  1540. { size = sizeof(target_system_pointer) }
  1541. size:=sizeof(pint);
  1542. offset:=tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)
  1543. end;
  1544. end;
  1545. { if something comes after the procsym, it's invalid assembler syntax }
  1546. GetRecordOffsetSize:=(s='');
  1547. exit;
  1548. end;
  1549. else
  1550. ;
  1551. end;
  1552. end;
  1553. { Support Field.Type as typecasting }
  1554. if (st=nil) and (s<>'') then
  1555. begin
  1556. asmsearchsym(s,sym,srsymtable);
  1557. if assigned(sym) and (sym.typ=typesym) then
  1558. begin
  1559. size:=ttypesym(sym).typedef.size;
  1560. s:='';
  1561. hastypecast:=true;
  1562. end;
  1563. end;
  1564. GetRecordOffsetSize:=(s='');
  1565. end;
  1566. Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
  1567. var
  1568. sym : tsym;
  1569. srsymtable : TSymtable;
  1570. hs : string;
  1571. Begin
  1572. hl:=nil;
  1573. SearchLabel:=false;
  1574. { Check for pascal labels, which are case insensetive }
  1575. hs:=upper(s);
  1576. asmsearchsym(hs,sym,srsymtable);
  1577. if sym=nil then
  1578. exit;
  1579. case sym.typ of
  1580. labelsym :
  1581. begin
  1582. if symtablestack.top.symtablelevel<>srsymtable.symtablelevel then
  1583. begin
  1584. Tlabelsym(sym).nonlocal:=true;
  1585. if emit then
  1586. include(current_procinfo.flags,pi_has_interproclabel);
  1587. end;
  1588. if not(assigned(tlabelsym(sym).asmblocklabel)) then
  1589. if Tlabelsym(sym).nonlocal then
  1590. current_asmdata.getglobaljumplabel(tlabelsym(sym).asmblocklabel)
  1591. else
  1592. current_asmdata.getjumplabel(tlabelsym(sym).asmblocklabel);
  1593. hl:=tlabelsym(sym).asmblocklabel;
  1594. if emit then
  1595. begin
  1596. if tlabelsym(sym).defined then
  1597. Message(sym_e_label_already_defined);
  1598. tlabelsym(sym).defined:=true
  1599. end
  1600. else
  1601. tlabelsym(sym).used:=true;
  1602. SearchLabel:=true;
  1603. end;
  1604. else
  1605. ;
  1606. end;
  1607. end;
  1608. {*************************************************************************}
  1609. { Instruction Generation Utilities }
  1610. {*************************************************************************}
  1611. Procedure ConcatString(p : TAsmList;s:string);
  1612. {*********************************************************************}
  1613. { PROCEDURE ConcatString(s:string); }
  1614. { Description: This routine adds the character chain pointed to in }
  1615. { s to the instruction linked list. }
  1616. {*********************************************************************}
  1617. Begin
  1618. p.concat(Tai_string.Create(s));
  1619. end;
  1620. Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);
  1621. {*********************************************************************}
  1622. { PROCEDURE ConcatConstant(value: aint; maxvalue: aint); }
  1623. { Description: This routine adds the value constant to the current }
  1624. { instruction linked list. }
  1625. { maxvalue -> indicates the size of the data to initialize: }
  1626. { $ff -> create a byte node. }
  1627. { $ffff -> create a word node. }
  1628. { $ffffffff -> create a dword node. }
  1629. {*********************************************************************}
  1630. var
  1631. rangelo,rangehi : int64;
  1632. Begin
  1633. case constsize of
  1634. 1 :
  1635. begin
  1636. p.concat(Tai_const.Create_8bit(byte(value)));
  1637. rangelo:=low(shortint);
  1638. rangehi:=high(byte);
  1639. end;
  1640. 2 :
  1641. begin
  1642. p.concat(Tai_const.Create_16bit(word(value)));
  1643. rangelo:=low(smallint);
  1644. rangehi:=high(word);
  1645. end;
  1646. 4 :
  1647. begin
  1648. p.concat(Tai_const.Create_32bit(longint(value)));
  1649. rangelo:=low(longint);
  1650. rangehi:=high(cardinal);
  1651. end;
  1652. 8 :
  1653. begin
  1654. p.concat(Tai_const.Create_64bit(int64(value)));
  1655. rangelo:=0;
  1656. rangehi:=0;
  1657. end;
  1658. else
  1659. internalerror(200405011);
  1660. end;
  1661. { check for out of bounds }
  1662. if (rangelo<>0) and
  1663. ((value>rangehi) or (value<rangelo)) then
  1664. Message(asmr_e_constant_out_of_bounds);
  1665. end;
  1666. Procedure ConcatConstSymbol(p : TAsmList;const sym:string;symtyp:tasmsymtype;l:tcgint;constsize:byte;isofs:boolean);
  1667. begin
  1668. {$ifdef i8086}
  1669. { 'DW xx' as well as 'DW OFFSET xx' are just near pointers }
  1670. if constsize=2 then
  1671. p.concat(Tai_const.Createname_near(sym,l))
  1672. else if constsize=4 then
  1673. begin
  1674. if isofs then
  1675. begin
  1676. { 'DD OFFSET xx' is a 32-bit offset; since we don't produce 32-bit
  1677. relocations yet, just do a 16-bit one and set the high word to 0 }
  1678. p.concat(Tai_const.Createname_near(sym,l));
  1679. p.concat(Tai_const.Create_16bit(0));
  1680. end
  1681. else
  1682. { 'DD xx' is a far pointer }
  1683. p.concat(Tai_const.Createname_far(sym,l));
  1684. end
  1685. else
  1686. internalerror(2018020701);
  1687. {$else i8086}
  1688. p.concat(Tai_const.Createname(sym,l));
  1689. {$endif i8086}
  1690. end;
  1691. Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);
  1692. {***********************************************************************}
  1693. { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }
  1694. { Description: This routine adds the value constant to the current }
  1695. { instruction linked list. }
  1696. { real_typ -> indicates the type of the real data to initialize: }
  1697. { s32real -> create a single node. }
  1698. { s64real -> create a double node. }
  1699. { s80real -> create an extended node. }
  1700. { s64bit -> create a comp node. }
  1701. { f32bit -> create a fixed node. (not used normally) }
  1702. {***********************************************************************}
  1703. Begin
  1704. case real_typ of
  1705. s32real : p.concat(tai_realconst.create_s32real(value));
  1706. s64real :
  1707. {$ifdef ARM}
  1708. if is_double_hilo_swapped then
  1709. p.concat(tai_realconst.create_s64real_hiloswapped(value))
  1710. else
  1711. {$endif ARM}
  1712. p.concat(tai_realconst.create_s64real(value));
  1713. s80real : p.concat(tai_realconst.create_s80real(value,s80floattype.size));
  1714. sc80real : p.concat(tai_realconst.create_s80real(value,sc80floattype.size));
  1715. s64comp : p.concat(tai_realconst.create_s64compreal(trunc(value)));
  1716. else
  1717. internalerror(2014050608);
  1718. end;
  1719. end;
  1720. Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);
  1721. {*********************************************************************}
  1722. { PROCEDURE ConcatLabel }
  1723. { Description: This routine either emits a label or a labeled }
  1724. { instruction to the linked list of instructions. }
  1725. {*********************************************************************}
  1726. begin
  1727. p.concat(Tai_label.Create(l));
  1728. end;
  1729. procedure ConcatAlign(p:TAsmList;l:tcgint);
  1730. {*********************************************************************}
  1731. { PROCEDURE ConcatPublic }
  1732. { Description: This routine emits an global definition to the }
  1733. { linked list of instructions.(used by AT&T styled asm) }
  1734. {*********************************************************************}
  1735. begin
  1736. p.concat(Tai_align.Create(l));
  1737. end;
  1738. procedure ConcatPublic(p:TAsmList;const s : string);
  1739. {*********************************************************************}
  1740. { PROCEDURE ConcatPublic }
  1741. { Description: This routine emits an global definition to the }
  1742. { linked list of instructions.(used by AT&T styled asm) }
  1743. {*********************************************************************}
  1744. begin
  1745. p.concat(Tai_symbol.Createname_global(s,AT_LABEL,0,voidcodepointertype));
  1746. end;
  1747. procedure ConcatLocal(p:TAsmList;const s : string);
  1748. {*********************************************************************}
  1749. { PROCEDURE ConcatLocal }
  1750. { Description: This routine emits an local definition to the }
  1751. { linked list of instructions. }
  1752. {*********************************************************************}
  1753. begin
  1754. p.concat(Tai_symbol.Createname(s,AT_LABEL,0,voidcodepointertype));
  1755. end;
  1756. end.