rautils.pas 57 KB

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