| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950 | {    Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman    This unit implements some support routines for assembler parsing    independent of the processor    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **********************************************************************}Unit RAUtils;{$i fpcdefs.inc}InterfaceUses  cutils,cclasses,  globtype,aasmbase,aasmtai,aasmdata,cpubase,cpuinfo,cgbase,cgutils,  symconst,symbase,symtype,symdef,symsym,constexp,symcpu;Const  RPNMax = 10;             { I think you only need 4, but just to be safe }  OpMax  = 25;Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;{---------------------------------------------------------------------                 Instruction management---------------------------------------------------------------------}type  TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,            OPR_REFERENCE,OPR_REGISTER,OPR_COND,OPR_REGSET,            OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG,            OPR_REGPAIR,OPR_FENCEFLAGS,OPR_INDEXEDREG);  TOprRec = record    case typ:TOprType of      OPR_NONE      : ();{$if defined(AVR)}      OPR_CONSTANT  : (val:longint);{$elseif defined(i8086)}      OPR_CONSTANT  : (val:longint);{$elseif defined(Z80)}      OPR_CONSTANT  : (val:longint);{$else}      OPR_CONSTANT  : (val:aint);{$endif}      OPR_SYMBOL    : (symbol:tasmsymbol;symofs:aint;symseg:boolean;sym_farproc_entry:boolean);      OPR_REFERENCE : (varsize:asizeint; constoffset: asizeint;ref_farproc_entry:boolean;ref:treference);      OPR_LOCAL     : (localvarsize, localconstoffset: asizeint;localsym:tabstractnormalvarsym;localsymofs:aint;localsegment,localindexreg:tregister;localscale:byte;localgetoffset,localforceref:boolean);      OPR_REGISTER  : (reg:tregister);{$ifdef m68k}      OPR_REGSET    : (regsetdata,regsetaddr,regsetfpu : tcpuregisterset);      OPR_REGPAIR   : (reghi,reglo: tregister);{$endif m68k}{$ifdef powerpc}      OPR_COND      : (cond : tasmcond);{$endif powerpc}{$ifdef POWERPC64}      OPR_COND      : (cond : tasmcond);{$endif POWERPC64}{$ifdef arm}      OPR_REGSET    : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister; usermode: boolean);      OPR_SHIFTEROP : (shifterop : tshifterop);      OPR_COND      : (cc : tasmcond);      OPR_MODEFLAGS : (flags : tcpumodeflags);      OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags);{$endif arm}{$ifdef aarch64}      OPR_REGSET    : (basereg: tregister; nregs, regsetindex: byte);      OPR_INDEXEDREG: (indexedreg: tregister; regindex: byte);      OPR_SHIFTEROP : (shifterop : tshifterop);      OPR_COND      : (cc : tasmcond);{$endif aarch64}{$if defined(riscv32) or defined(riscv64)}      OPR_FENCEFLAGS: (fenceflags : TFenceFlags);{$endif aarch64}  end;  TInstruction = class;  TOperand = class    opr    : TOprRec;    typesize : byte;    haslabelref,      { if the operand has a label, used in a reference like a                        var (e.g. 'mov ax, word ptr [label+5]', but *not*                        e.g. 'jmp label') }    hasproc,          { if the operand has a procedure/function reference }    hastype,          { if the operand has typecasted variable }    hasvar : boolean; { if the operand is loaded with a variable }    size   : TCGSize;    constructor create;virtual;    destructor  destroy;override;    Procedure SetSize(_size:longint;force:boolean);virtual;    Procedure SetCorrectSize(opcode:tasmop);virtual;    Function  SetupResult:boolean;virtual;    Function  SetupSelf:boolean;    Function  SetupOldEBP:boolean;    Function  SetupVar(const s:string;GetOffset : boolean): Boolean;    function CheckOperand(ins : TInstruction): boolean; virtual;    Procedure InitRef;    Procedure InitRefConvertLocal;   protected    Procedure InitRefError;  end;  TCOperand = class of TOperand;  TInstruction = class    operands  : array[1..max_operands] of toperand;    opcode    : tasmop;    condition : tasmcond;    ops       : byte;    labeled   : boolean;    filepos  : tfileposinfo;    constructor create(optype : tcoperand);virtual;    destructor  destroy;override;    { converts the instruction to an instruction how it's used by the assembler writer      and concats it to the passed list. The newly created item is returned if the      instruction was valid, otherwise nil is returned }    function ConcatInstruction(p:TAsmList) : tai;virtual;  end;  {---------------------------------------------------------------------}  {                   Expression parser types                           }  {---------------------------------------------------------------------}   TExprOperator = record    ch: char;           { operator }    is_prefix: boolean; { was it a prefix, possible prefixes are +,- and not }   end;  {**********************************************************************}  { The following operators are supported:                              }  {  '+' : addition                                                     }  {  '-' : subtraction                                                  }  {  '*' : multiplication                                               }  {  '/' : modulo division                                              }  {  '^' : exclusive or                                                 }  {  '<' : shift left                                                   }  {  '>' : shift right                                                  }  {  '&' : bitwise and                                                  }  {  '|' : bitwise or                                                   }  {  '~' : bitwise complement                                           }  {  '%' : modulo division                                              }  {  nnn: longint numbers                                               }  {  ( and ) parenthesis                                                }  {  [ and ] another kind of parenthesis                                }  {**********************************************************************}  TExprParse = class    public     Constructor create;     Destructor Destroy;override;     Function Evaluate(Expr:  String): tcgint;     Function Priority(_Operator: Char): aint;    private     RPNStack   : Array[1..RPNMax] of tcgint;        { Stack For RPN calculator }     RPNTop     : tcgint;     OpStack    : Array[1..OpMax] of TExprOperator;    { Operator stack For conversion }     OpTop      : tcgint;     Procedure RPNPush(Num: tcgint);     Function RPNPop: tcgint;     Procedure RPNCalc(const token: String; prefix: boolean);     Procedure OpPush(_Operator: char; prefix: boolean);     { In reality returns TExprOperaotr }     Procedure OpPop(var _Operator:TExprOperator);  end;  { Evaluate an expression string to a tcgint }  Function CalculateExpression(const expression: string): tcgint;  {---------------------------------------------------------------------}  {                     String routines                                 }  {---------------------------------------------------------------------}Function ParseVal(const S:String;base:byte):tcgint;Function PadZero(Var s: String; n: byte): Boolean;Function EscapeToPascal(const s:string): string;{---------------------------------------------------------------------                     Symbol helper routines---------------------------------------------------------------------}procedure AsmSearchSym(const s:string;out srsym:tsym;out srsymtable:TSymtable);Function GetRecordOffsetSize(s:string;out Offset: tcgint;out Size:tcgint; out mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;Function SearchType(const hs:string;out size:tcgint): Boolean;Function SearchRecordType(const s:string): boolean;Function SearchIConstant(const s:string; var l:tcgint): boolean;Function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;{---------------------------------------------------------------------                  Instruction generation routines---------------------------------------------------------------------}  Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);  Procedure ConcatConstant(p : TAsmList;value: tcgint; constsize:byte);  Procedure ConcatConstSymbol(p : TAsmList;const sym,endsym:string;symtyp:tasmsymtype;l:tcgint;constsize:byte;isofs:boolean);  Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);  Procedure ConcatString(p : TAsmList;s:string);  procedure ConcatAlign(p:TAsmList;l:tcgint);  Procedure ConcatPublic(p:TAsmList;const s : string);  Procedure ConcatLocal(p:TAsmList;const s : string);Implementationuses  SysUtils,  defutil,systems,verbose,globals,  symtable,paramgr,  aasmcpu,  procinfo,ngenutil;{*************************************************************************                              TExprParse*************************************************************************}Constructor TExprParse.create;Beginend;Procedure TExprParse.RPNPush(Num : tcgint);{ Add an operand to the top of the RPN stack }begin  if RPNTop < RPNMax then   begin     Inc(RPNTop);     RPNStack[RPNTop]:=Num;   end  else   Message(asmr_e_expr_illegal);end;Function TExprParse.RPNPop : tcgint;{ Get the operand at the top of the RPN stack }begin  RPNPop:=0;  if RPNTop > 0 then   begin     RPNPop:=RPNStack[RPNTop];     Dec(RPNTop);   end  else   Message(asmr_e_expr_illegal);end;Procedure TExprParse.RPNCalc(const Token : String; prefix:boolean);                       { RPN Calculator }Var  Temp  : tcgint;  n1,n2 : tcgint;  LocalError : Integer;begin  { Handle operators }  if (Length(Token) = 1) and (Token[1] in ['+', '-', '*', '/','&','|','%','^','~','<','>']) then   Case Token[1] of    '+' :      Begin        if not prefix then         RPNPush(RPNPop + RPNPop);      end;    '-' :      Begin        if prefix then         RPNPush(-(RPNPop))        else         begin           n1:=RPNPop;           n2:=RPNPop;           RPNPush(n2 - n1);         end;      end;    '*' : RPNPush(RPNPop * RPNPop);    '&' :      begin        n1:=RPNPop;        n2:=RPNPop;        RPNPush(n2 and n1);      end;    '|' :      begin        n1:=RPNPop;        n2:=RPNPop;        RPNPush(n2 or n1);      end;    '~' : RPNPush(NOT RPNPop);    '<' :      begin        n1:=RPNPop;        n2:=RPNPop;        RPNPush(n2 SHL n1);      end;    '>' :      begin        n1:=RPNPop;        n2:=RPNPop;        RPNPush(n2 SHR n1);      end;    '%' :      begin        Temp:=RPNPop;        if Temp <> 0 then         RPNPush(RPNPop mod Temp)        else         begin           Message(asmr_e_expr_zero_divide);           { push 1 for error recovery }           RPNPush(1);         end;      end;    '^' : RPNPush(RPNPop XOR RPNPop);    '/' :      begin        Temp:=RPNPop;        if Temp <> 0 then         RPNPush(RPNPop div Temp)        else         begin           Message(asmr_e_expr_zero_divide);           { push 1 for error recovery }           RPNPush(1);         end;      end;   end  else   begin     { Convert String to number and add to stack }      Val(Token, Temp, LocalError);     if LocalError = 0 then      RPNPush(Temp)     else      begin        Message(asmr_e_expr_illegal);        { push 1 for error recovery }        RPNPush(1);      end;   end;end;Procedure TExprParse.OpPush(_Operator : char;prefix: boolean);{ Add an operator onto top of the stack }begin  if OpTop < OpMax then   begin     Inc(OpTop);     OpStack[OpTop].ch:=_Operator;     OpStack[OpTop].is_prefix:=prefix;   end  else   Message(asmr_e_expr_illegal);end;Procedure TExprParse.OpPop(var _Operator:TExprOperator);{ Get operator at the top of the stack }begin  if OpTop > 0 then   begin     _Operator:=OpStack[OpTop];     Dec(OpTop);   end  else   Message(asmr_e_expr_illegal);end;Function TExprParse.Priority(_Operator : Char) : aint;{ Return priority of operator }{ The greater the priority, the higher the precedence }begin  Priority:=0;  Case _Operator OF    '(','[' :      Priority:=0;    '|','^','~' :             // the lowest priority: OR, XOR, NOT      Priority:=0;    '&' :                     // bigger priority: AND      Priority:=1;    '+', '-' :                // bigger priority: +, -      Priority:=2;    '*', '/','%','<','>' :   // the highest priority: *, /, MOD, SHL, SHR      Priority:=3;    else      Message(asmr_e_expr_illegal);  end;end;Function TExprParse.Evaluate(Expr : String):tcgint;Var  I     : longint;  Token : String;  opr   : TExprOperator;begin  Evaluate:=0;  { Reset stacks }  OpTop :=0;  RPNTop:=0;  Token :='';  { nothing to do ? }  if Expr='' then   exit;  For I:=1 to Length(Expr) DO   begin     if Expr[I] in ['0'..'9'] then      begin       { Build multi-digit numbers }        Token:=Token + Expr[I];        if I = Length(Expr) then          { Send last one to calculator }         RPNCalc(Token,false);      end     else      if Expr[I] in ['+', '-', '*', '/', '(', ')','[',']','^','&','|','%','~','<','>'] then       begin         if Token <> '' then          begin        { Send last built number to calc. }            RPNCalc(Token,false);            Token:='';          end;         Case Expr[I] OF          '[' : OpPush('[',false);          ']' : begin                  While (OpTop>0) and (OpStack[OpTop].ch <> '[') DO                   Begin                     OpPop(opr);                     RPNCalc(opr.ch,opr.is_prefix);                   end;                  OpPop(opr);                          { Pop off and ignore the '[' }                end;          '(' : OpPush('(',false);          ')' : begin                  While (OpTop>0) and (OpStack[OpTop].ch <> '(') DO                   Begin                     OpPop(opr);                     RPNCalc(opr.ch,opr.is_prefix);                   end;                  OpPop(opr);                          { Pop off and ignore the '(' }                end;  '+','-','~' : Begin                  { workaround for -2147483648 }                  if (expr[I]='-') and (expr[i+1] in ['0'..'9']) then                   begin                     token:='-';                     expr[i]:='+';                   end;                  { if start of expression then surely a prefix }                  { or if previous char was also an operator    }                  if (I = 1) or (not (Expr[I-1] in ['0'..'9',')'])) then                    OpPush(Expr[I],true)                  else                    Begin                    { Evaluate all higher priority operators }                      While (OpTop > 0) AND (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO                       Begin                         OpPop(opr);                         RPNCalc(opr.ch,opr.is_prefix);                       end;                      OpPush(Expr[I],false);                    End;                end;     '*', '/',  '^','|','&',  '%','<','>' : begin                  While (OpTop > 0) and (Priority(Expr[I]) <= Priority(OpStack[OpTop].ch)) DO                   Begin                     OpPop(opr);                     RPNCalc(opr.ch,opr.is_prefix);                   end;                  OpPush(Expr[I],false);                end;         end; { Case }       end     else      Message(asmr_e_expr_illegal);  { Handle bad input error }   end;{ Pop off the remaining operators }  While OpTop > 0 do   Begin     OpPop(opr);     RPNCalc(opr.ch,opr.is_prefix);   end;{ The result is stored on the top of the stack }  Evaluate:=RPNPop;end;Destructor TExprParse.Destroy;Beginend;Function CalculateExpression(const expression: string): tcgint;var  expr: TExprParse;Begin  expr:=TExprParse.create;  CalculateExpression:=expr.Evaluate(expression);  expr.Free;end;{*************************************************************************}{                         String conversions/utils                        }{*************************************************************************}Function EscapeToPascal(const s:string): string;{ converts a C styled string - which contains escape }{ characters to a pascal style string.               }var  i,len : asizeint;  hs    : string;  temp  : string;  c     : char;Begin  hs:='';  len:=0;  i:=0;  while (i<length(s)) and (len<255) do   begin     Inc(i);     if (s[i]='\') and (i<length(s)) then      Begin        inc(i);        case s[i] of         '\' :           c:='\';         'b':           c:=#8;         'f':           c:=#12;         'n':           c:=#10;         'r':           c:=#13;         't':           c:=#9;         '"':           c:='"';         '0'..'7':           Begin             temp:=s[i];             temp:=temp+s[i+1];             temp:=temp+s[i+2];             inc(i,2);             c:=chr(ParseVal(temp,8));           end;         'x':           Begin             temp:=s[i+1];             temp:=temp+s[i+2];             inc(i,2);             c:=chr(ParseVal(temp,16));           end;         else           Begin             Message1(asmr_e_escape_seq_ignored,s[i]);             c:=s[i];           end;        end;      end     else      c:=s[i];     inc(len);     hs[len]:=c;   end;  hs[0]:=chr(len);  EscapeToPascal:=hs;end;Function ParseVal(const S:String;base:byte):tcgint;{ Converts a decimal string to tcgint }var  code : integer;  errmsg : word;  prefix : string[2];Begin  case base of    2 :      begin        errmsg:=asmr_e_error_converting_binary;        prefix:='%';      end;    8 :      begin        errmsg:=asmr_e_error_converting_octal;        prefix:='&';      end;    10 :      begin        errmsg:=asmr_e_error_converting_decimal;        prefix:='';      end;    16 :      begin        errmsg:=asmr_e_error_converting_hexadecimal;        prefix:='$';      end;    else      internalerror(200501202);  end;  val(prefix+s,result,code);  if code<>0 then    begin      val(prefix+s,result,code);      if code<>0 then        begin          Message1(errmsg,s);          result:=0;        end;    end;end;Function PadZero(Var s: String; n: byte): Boolean;Begin  PadZero:=TRUE;  { Do some error checking first }  if Length(s) = n then    exit  else  if Length(s) > n then  Begin    PadZero:=FALSE;    delete(s,n+1,length(s));    exit;  end  else    PadZero:=TRUE;  { Fill it up with the specified character }  fillchar(s[length(s)+1],n-1,#0);  s[0]:=chr(n);end;{****************************************************************************                                   TOperand****************************************************************************}constructor TOperand.Create;begin  size:=OS_NO;  hasproc:=false;  hastype:=false;  hasvar:=false;  FillChar(Opr,sizeof(Opr),0);end;destructor TOperand.destroy;beginend;Procedure TOperand.SetSize(_size:longint;force:boolean);begin  if force or     ((size = OS_NO) and (_size<=16)) then   Begin     case _size of        1 : size:=OS_8;        2 : size:=OS_16{ could be S_IS};        4 : size:=OS_32{ could be S_IL or S_FS};        8 : size:=OS_64{ could be S_D or S_FL};       10 : size:=OS_F80;       16 : size:=OS_128;     end;   end;end;Procedure TOperand.SetCorrectSize(opcode:tasmop);beginend;function TOperand.SetupResult:boolean;begin  SetupResult:=false;  { replace by correct offset. }  with current_procinfo.procdef do    if (not is_void(returndef)) then      begin        if (m_tp7 in current_settings.modeswitches) and          not (df_generic in defoptions) and          (po_assembler in procoptions) and          (not paramanager.ret_in_param(returndef,current_procinfo.procdef)) then          begin            message(asmr_e_cannot_use_RESULT_here);            exit;          end;        SetupResult:=setupvar('result',false)      end    else      message(asmr_e_void_function);end;Function TOperand.SetupSelf:boolean;Begin  SetupSelf:=false;  if assigned(current_structdef) then    SetupSelf:=setupvar('self',false)  else    Message(asmr_e_cannot_use_SELF_outside_a_method);end;Function TOperand.SetupOldEBP:boolean;Begin  SetupOldEBP:=false;  if current_procinfo.procdef.parast.symtablelevel>normal_function_level then    SetupOldEBP:=setupvar('parentframe',false)  else    Message(asmr_e_cannot_use_OLDEBP_outside_nested_procedure);end;Function TOperand.SetupVar(const s:string;GetOffset : boolean): Boolean;  function symtable_has_localvarsyms(st:TSymtable):boolean;  var    sym : tsym;    i   : longint;  begin    result:=false;    for i:=0 to st.SymList.Count-1 do      begin        sym:=tsym(st.SymList[i]);        if sym.typ=localvarsym then          begin            result:=true;            exit;          end;      end;  end;  procedure setconst(l:aint);  begin    { We return the address of the field, just like Delphi/TP }    case opr.typ of      OPR_NONE :        begin          opr.typ:=OPR_CONSTANT;          opr.val:=l;        end;      OPR_CONSTANT :        inc(opr.val,l);      OPR_REFERENCE :        inc(opr.ref.offset,l);      OPR_LOCAL :        inc(opr.localsymofs,l);      else        Message(asmr_e_invalid_operand_type);    end;  end;  procedure setvarsize(sym: tabstractvarsym);  var    harrdef: tarraydef;    l: asizeint;  begin    case sym.vardef.typ of      orddef,      enumdef,      pointerdef,      procvardef,      floatdef :        SetSize(sym.getsize,false);      arraydef :        begin          { for arrays try to get the element size, take care of            multiple indexes }          harrdef:=tarraydef(sym.vardef);          { calc array size }          if is_special_array(harrdef) then             l := -1           else             l := harrdef.size;          case opr.typ of            OPR_REFERENCE: opr.varsize := l;                OPR_LOCAL: opr.localvarsize := l;            else              ;          end;          while assigned(harrdef.elementdef) and                (harrdef.elementdef.typ=arraydef) do           harrdef:=tarraydef(harrdef.elementdef);          if not is_packed_array(harrdef) then            SetSize(harrdef.elesize,false)           else               if (harrdef.elepackedbitsize mod 8) = 0 then                 SetSize(harrdef.elepackedbitsize div 8,false);        end;      recorddef:        case opr.typ of          OPR_REFERENCE: opr.varsize := sym.getsize;              OPR_LOCAL: opr.localvarsize := sym.getsize;          else            ;        end;      else        ;    end;  end;{ search and sets up the correct fields in the Instr record }{ for the NON-constant identifier passed to the routine.    }{ if not found returns FALSE.                               }var  sym : tsym;  srsymtable : TSymtable;{$ifdef x86}  segreg,{$endif x86}  indexreg : tregister;  plist : ppropaccesslistitem;  size_set_from_absolute : boolean = false;  { offset fixup (in bytes), coming from an absolute declaration with an index    (e.g. var tralala: word absolute moo[5]; ) }  absoffset: asizeint=0;  harrdef: tarraydef;  tmpprocinfo: tprocinfo;Begin  SetupVar:=false;  asmsearchsym(s,sym,srsymtable);  if sym = nil then   exit;  if sym.typ=absolutevarsym then    begin      case tabsolutevarsym(sym).abstyp of        tovar:          begin            { Only support simple loads }            plist:=tabsolutevarsym(sym).ref.firstsym;            if assigned(plist) and               (plist^.sltype=sl_load) then              begin                setvarsize(tabstractvarsym(sym));                size_set_from_absolute:=true;                sym:=plist^.sym;                { Check if address can be resolved, but only if not an array }                if (sym.typ=absolutevarsym) and (tabsolutevarsym(sym).abstyp=toaddr) and not                  (assigned(plist^.next) and (plist^.next^.sltype=sl_vec)) then                  begin                    initref;                    opr.ref.offset:=tabsolutevarsym(sym).addroffset;                    hasvar:=true;                    Result:=true;                    exit;                  end;                { resolve the chain of array indexes (if there are any) }                harrdef:=nil;                while assigned(plist^.next) do                  begin                    plist:=plist^.next;                    if (plist^.sltype=sl_vec) and (tabstractvarsym(sym).vardef.typ=arraydef) then                      begin                        if harrdef=nil then                          harrdef:=tarraydef(tabstractvarsym(sym).vardef)                        else if harrdef.elementdef.typ=arraydef then                          harrdef:=tarraydef(harrdef.elementdef)                        else                          begin                            Message(asmr_e_unsupported_symbol_type);                            exit;                          end;                        if is_special_array(harrdef) then                          begin                            Message(asmr_e_unsupported_symbol_type);                            exit;                          end;                        if not is_packed_array(harrdef) then                          Inc(absoffset,asizeint(Int64(plist^.value-harrdef.lowrange))*harrdef.elesize)                        else if (Int64(plist^.value-harrdef.lowrange)*harrdef.elepackedbitsize mod 8)=0 then                          Inc(absoffset,asizeint(Int64(plist^.value-harrdef.lowrange)*harrdef.elepackedbitsize div 8))                        else                          Message(asmr_e_packed_element);                      end                    else                      begin                        Message(asmr_e_unsupported_symbol_type);                        exit;                      end;                  end;              end            else              begin                Message(asmr_e_unsupported_symbol_type);                exit;              end;          end;        toaddr:          begin            initref;            opr.ref.offset:=tabsolutevarsym(sym).addroffset;            setvarsize(tabstractvarsym(sym));            size_set_from_absolute:=true;            hasvar:=true;            Result:=true;            exit;          end;        else          begin            Message(asmr_e_unsupported_symbol_type);            exit;          end;      end;    end;  case sym.typ of    fieldvarsym :      begin        if not tabstractrecordsymtable(sym.owner).is_packed then          setconst(absoffset+tfieldvarsym(sym).fieldoffset)        else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then          setconst(absoffset+tfieldvarsym(sym).fieldoffset div 8)        else          Message(asmr_e_packed_element);        if not size_set_from_absolute then          setvarsize(tabstractvarsym(sym));        hasvar:=true;        SetupVar:=true;      end;    staticvarsym,    localvarsym,    paravarsym :      begin        { we always assume in asm statements that     }        { that the variable is valid.                 }        tabstractvarsym(sym).varstate:=vs_readwritten;        inc(tabstractvarsym(sym).refs);        { variable can't be placed in a register }        tabstractvarsym(sym).varregable:=vr_none;        { and anything may happen with its address }        tabstractvarsym(sym).addr_taken:=true;        case sym.typ of          staticvarsym :            begin              initref;              opr.ref.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(sym).mangledname,AT_DATA);              Inc(opr.ref.offset,absoffset);            end;          paravarsym,          localvarsym :            begin              tmpprocinfo:=current_procinfo;              while assigned(tmpprocinfo) do                begin                  if (sym.owner=tmpprocinfo.procdef.localst) or                     (sym.owner=tmpprocinfo.procdef.parast) then                    begin                      tmpprocinfo.procdef.init_paraloc_info(calleeside);                      break;                    end;                  tmpprocinfo:=tmpprocinfo.parent;                end;              if opr.typ=OPR_REFERENCE then                begin{$ifdef x86}                  segreg:=opr.ref.segment;{$endif x86}                  indexreg:=opr.ref.base;                  if opr.ref.index<>NR_NO then                    begin                      if indexreg=NR_NO then                        indexreg:=opr.ref.index                      else                        Message(asmr_e_multiple_index);                    end;                end              else                begin{$ifdef x86}                  segreg:=NR_NO;{$endif x86}                  indexreg:=NR_NO;                end;              opr.typ:=OPR_LOCAL;              if assigned(current_procinfo.parent) and                 not(po_inline in current_procinfo.procdef.procoptions) and                 (sym.owner<>current_procinfo.procdef.localst) and                 (sym.owner<>current_procinfo.procdef.parast) and                 (current_procinfo.procdef.localst.symtablelevel>normal_function_level) and                 symtable_has_localvarsyms(current_procinfo.procdef.localst) then                message1(asmr_e_local_para_unreachable,s);              opr.localsym:=tabstractnormalvarsym(sym);              opr.localsymofs:=absoffset;{$ifdef x86}              opr.localsegment:=segreg;{$endif x86}              opr.localindexreg:=indexreg;              opr.localscale:=0;              opr.localgetoffset:=GetOffset;              if paramanager.push_addr_param(tabstractvarsym(sym).varspez,tabstractvarsym(sym).vardef,current_procinfo.procdef.proccalloption) then                SetSize(sizeof(pint),false);            end;          else            ;        end;        if not size_set_from_absolute then          setvarsize(tabstractvarsym(sym));        hasvar:=true;        SetupVar:=true;        Exit;      end;    constsym :      begin        if tconstsym(sym).consttyp=constord then         begin           setconst(tconstsym(sym).value.valueord.svalue);           SetupVar:=true;           Exit;         end;      end;    typesym :      begin        if ttypesym(sym).typedef.typ in [recorddef,objectdef] then         begin           setconst(0);           SetupVar:=TRUE;           Exit;         end;      end;    procsym :      begin        if Tprocsym(sym).ProcdefList.Count>1 then          Message(asmr_w_calling_overload_func);        case opr.typ of          OPR_REFERENCE:            begin              opr.ref.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);              Inc(opr.ref.offset,absoffset);{$ifdef i8086}              opr.ref_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))                        and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);{$endif i8086}            end;          OPR_NONE:            begin              opr.typ:=OPR_SYMBOL;              opr.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION);{$ifdef i8086}              opr.sym_farproc_entry:=is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))                        and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions);{$endif i8086}              opr.symofs:=absoffset;            end;        else          Message(asmr_e_invalid_operand_type);        end;        hasproc:=true;        hasvar:=true;        SetupVar:=TRUE;        Exit;      end;{$ifdef i8086}    labelsym :      begin        case opr.typ of          OPR_REFERENCE:            begin              opr.ref.symbol:=current_asmdata.RefAsmSymbol(tlabelsym(sym).mangledname,AT_FUNCTION);              Inc(opr.ref.offset,absoffset);              if opr.ref.segment=NR_NO then                opr.ref.segment:=NR_CS;            end;          else            begin              Message(asmr_e_unsupported_symbol_type);              exit;            end;        end;        haslabelref:=true;        hasvar:=true;        SetupVar:=TRUE;        Exit;      end{$endif i8086}    else      begin        Message(asmr_e_unsupported_symbol_type);        exit;      end;  end;end;procedure TOperand.InitRef;{*********************************************************************}{  Description: This routine first check if the opcode is of          }{  type OPR_NONE, or OPR_REFERENCE , if not it gives out an error.    }{  If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up  }{  the operand type to OPR_REFERENCE, as well as setting up the ref   }{  to point to the default segment.                                   }{*********************************************************************}var  l : aint;  hsymofs : aint;  hsymbol : tasmsymbol;  reg : tregister;  hsym_farprocentry: Boolean;Begin  case opr.typ of    OPR_REFERENCE :      exit;    OPR_CONSTANT :      begin        l:=opr.val;        opr.typ:=OPR_REFERENCE;        Fillchar(opr.ref,sizeof(treference),0);        opr.Ref.Offset:=l;        opr.varsize:=0;        opr.constoffset:=0;        opr.ref_farproc_entry:=false;      end;    OPR_NONE :      begin        opr.typ:=OPR_REFERENCE;        opr.varsize:=0;        opr.constoffset:=0;        opr.ref_farproc_entry:=false;        Fillchar(opr.ref,sizeof(treference),0);      end;    OPR_REGISTER :      begin        reg:=opr.reg;        opr.typ:=OPR_REFERENCE;        opr.varsize:=0;        opr.constoffset:=0;        opr.ref_farproc_entry:=false;        Fillchar(opr.ref,sizeof(treference),0);        opr.Ref.base:=reg;      end;    OPR_SYMBOL :      begin        hsymbol:=opr.symbol;        hsymofs:=opr.symofs;        hsym_farprocentry:=opr.sym_farproc_entry;        opr.typ:=OPR_REFERENCE;        opr.varsize:=0;        opr.constoffset:=0;        Fillchar(opr.ref,sizeof(treference),0);        opr.ref.symbol:=hsymbol;        opr.ref.offset:=hsymofs;        opr.ref_farproc_entry:=hsym_farprocentry;      end;    else      InitRefError;    end;end;procedure TOperand.InitRefConvertLocal;var  localvarsize,localconstoffset: asizeint;  localsym:tabstractnormalvarsym;  localsymofs:aint;{$ifdef x86}  localsegment,{$endif x86}  localindexreg:tregister;  localscale:byte;begin  if opr.typ=OPR_LOCAL then    begin      if AsmRegisterPara(opr.localsym) and         not opr.localgetoffset then        begin          localvarsize:=opr.localvarsize;          localconstoffset:=opr.localconstoffset;          localsym:=opr.localsym;          localsymofs:=opr.localsymofs;{$ifdef x86}          localsegment:=opr.localsegment;{$endif x86}          localindexreg:=opr.localindexreg;          localscale:=opr.localscale;          opr.typ:=OPR_REFERENCE;          hasvar:=false;          Fillchar(opr.ref,sizeof(treference),0);          opr.varsize:=localvarsize;          opr.constoffset:=localconstoffset;          opr.ref_farproc_entry:=false;          opr.ref.base:=tparavarsym(localsym).paraloc[calleeside].Location^.register;          opr.ref.offset:=localsymofs;{$ifdef x86}          opr.ref.segment:=localsegment;{$endif x86}          opr.ref.index:=localindexreg;          opr.ref.scalefactor:=localscale;        end      else        InitRefError;    end  else    InitRef;end;procedure TOperand.InitRefError;begin  Message(asmr_e_invalid_operand_type);  { Recover }  opr.typ:=OPR_REFERENCE;  opr.varsize:=0;  opr.constoffset:=0;  opr.ref_farproc_entry:=false;  Fillchar(opr.ref,sizeof(treference),0);end;Function TOperand.CheckOperand(ins : TInstruction): boolean;{*********************************************************************}{  Description: This routine checks if the operand is of              }{  valid, and returns false if it isn't. Does nothing by default.     }{*********************************************************************}begin  result:=true;end;{****************************************************************************                                 TInstruction****************************************************************************}constructor TInstruction.create(optype : tcoperand);  var    i : longint;  Begin    { these field are set to 0 anyways by the constructor helper (FK)    Opcode:=A_NONE;    Condition:=C_NONE;    Ops:=0;    }    filepos:=current_filepos;    for i:=1 to max_operands do      Operands[i]:=optype.create;    Labeled:=false;  end;destructor TInstruction.destroy;var  i : longint;Begin  for i:=1 to max_operands do   Operands[i].free;end;  function TInstruction.ConcatInstruction(p:TAsmList) : tai;    var      ai   : taicpu;      i : longint;    begin      for i:=1 to Ops do        operands[i].CheckOperand(self);      ai:=taicpu.op_none(opcode);      ai.fileinfo:=filepos;      ai.Ops:=Ops;      ai.Allocate_oper(Ops);      for i:=1 to Ops do        with operands[i].opr do          begin            case typ of              OPR_CONSTANT :                ai.loadconst(i-1,val);              OPR_REGISTER:                ai.loadreg(i-1,reg);              OPR_SYMBOL:                ai.loadsymbol(i-1,symbol,symofs);              OPR_LOCAL :                begin                  ai.loadlocal(i-1,localsym,localsymofs,localindexreg,                               localscale,localgetoffset,localforceref);{$ifdef x86}                  ai.oper[i-1]^.localoper^.localsegment:=localsegment;{$endif x86}                end;              OPR_REFERENCE:                ai.loadref(i-1,ref);{$ifdef m68k}              OPR_REGSET:                ai.loadregset(i-1,regsetdata,regsetaddr,regsetfpu);              OPR_REGPAIR:                ai.loadregpair(i-1,reghi,reglo);{$endif}{$ifdef ARM}              OPR_REGSET:                ai.loadregset(i-1,regtype,subreg,regset,usermode);              OPR_MODEFLAGS:                ai.loadmodeflags(i-1,flags);              OPR_SPECIALREG:                ai.loadspecialreg(i-1,specialreg,specialregflags);{$endif ARM}{$if defined(arm) or defined(aarch64)}             OPR_SHIFTEROP:               ai.loadshifterop(i-1,shifterop);             OPR_COND:               ai.loadconditioncode(i-1,cc);{$endif arm or aarch64}{$ifdef aarch64}              OPR_REGSET:                ai.loadregset(i-1,basereg,nregs,regsetindex);              OPR_INDEXEDREG:                ai.loadindexedreg(i-1,indexedreg,regindex);{$endif aarch64}{$if defined(riscv32) or defined(riscv64)}             OPR_FENCEFLAGS:               ai.loadfenceflags(i-1,fenceflags);{$endif riscv32 or riscv64}              { ignore wrong operand }              OPR_NONE:                ;              else                internalerror(200501051);            end;          end;     ai.SetCondition(condition);     { Concat the opcode or give an error }      if assigned(ai) then         p.concat(ai)      else       Message(asmr_e_invalid_opcode_and_operand);      result:=ai;    end;{****************************************************************************                      Symbol table helper routines****************************************************************************}procedure AddAbsoluteSymRefs(sym: tabsolutevarsym); forward;procedure MaybeAddSymRef(sym: tsym);begin  case sym.typ of     absolutevarsym:       AddAbsoluteSymRefs(tabsolutevarsym(sym));     staticvarsym:       if not(vo_is_external in tstaticvarsym(sym).varoptions) then         cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(sym.mangledname,AT_DATA),tstaticvarsym(sym).vardef,true);     procsym:       begin         { if it's a pure assembler routine, the definition of the symbol will also           be in assembler and it can't be removed by the compiler (and if we mark           it as used anyway, clang will get into trouble) }         if not(po_assembler in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions) and            not(po_external in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions) then           cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(tprocdef(tprocsym(sym).ProcdefList[0]).mangledname,AT_FUNCTION),tprocdef(tprocsym(sym).ProcdefList[0]),true);       end;     else       ;   end;end;procedure AddAbsoluteSymRefs(sym: tabsolutevarsym);var  symlist: ppropaccesslistitem;begin  case sym.abstyp of    toaddr:      ;    toasm:      begin        cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(sym.mangledname,AT_DATA),sym.vardef,true);      end;    tovar:      begin        symlist:=tabsolutevarsym(sym).ref.firstsym;        repeat          case symlist^.sltype of            sl_load:              MaybeAddSymRef(symlist^.sym);            sl_subscript,            sl_absolutetype,            sl_typeconv,            sl_vec:              ;            else              internalerror(2009031401);          end;          symlist:=symlist^.next;        until not assigned(symlist);      end;  end;end;procedure AsmSearchSym(const s:string;out srsym:tsym;out srsymtable:TSymtable);var  i : integer;begin  i:=pos('.',s);  { allow unit.identifier }  if i>1 then    begin      searchsym(Copy(s,1,i-1),srsym,srsymtable);      if assigned(srsym) then       begin         if (srsym.typ=unitsym) and            (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and            srsym.owner.iscurrentunit then           searchsym_in_module(tunitsym(srsym).module,Copy(s,i+1,255),srsym,srsymtable)         else           begin             srsym:=nil;             srsymtable:=nil;           end;       end;    end  else    searchsym(s,srsym,srsymtable);  { in asm routines, the function result variable, that matches the function    name should be avoided, because:    1) there's already a @Result directive (even in TP7) that can be used, if       you want to access the function result    2) there's no other way to disambiguate between the function result variable       and the function's address (using asm syntax only)    This fixes code, such as:    function test1: word;    begin      asm        mov ax, offset test1      end;    end;    and makes it work in a consistent manner as this code:    procedure test2;    begin      asm        mov ax, offset test2      end;    end; }  if assigned(srsym) and     assigned(srsymtable) and     (srsym.typ=absolutevarsym) and     (vo_is_funcret in tabsolutevarsym(srsym).varoptions) and     (srsymtable.symtabletype=localsymtable) and     assigned(srsymtable.defowner) and     (srsymtable.defowner.typ=procdef) and     (tprocdef(srsymtable.defowner).procsym.name=tabsolutevarsym(srsym).Name) then    begin      srsym:=tprocdef(srsymtable.defowner).procsym;      srsymtable:=srsym.Owner;    end;  { llvm can't catch symbol references from inline assembler blocks }  if assigned(srsym) then    MaybeAddSymRef(srsym);end;Function SearchType(const hs:string;out size:tcgint): Boolean;var  srsym : tsym;  srsymtable : TSymtable;begin  result:=false;  size:=0;  asmsearchsym(hs,srsym,srsymtable);  if assigned(srsym) and     (srsym.typ=typesym) then    begin      size:=ttypesym(srsym).typedef.size;      result:=true;    end;end;Function SearchRecordType(const s:string): boolean;var  srsym : tsym;  srsymtable : TSymtable;Begin  SearchRecordType:=false;{ Check the constants in symtable }  asmsearchsym(s,srsym,srsymtable);  if srsym <> nil then   Begin     case srsym.typ of       typesym :         begin           if ttypesym(srsym).typedef.typ in [recorddef,objectdef] then            begin              SearchRecordType:=true;              exit;            end;         end;       fieldvarsym :         begin           if (tfieldvarsym(srsym).vardef.typ in [recorddef,objectdef]) then             begin               SearchRecordType:=true;               exit;             end;         end;       else         ;     end;   end;end;Function SearchIConstant(const s:string; var l:tcgint): boolean;{**********************************************************************}{  Description: Searches for a CONSTANT of name s in either the local  }{  symbol list, then in the global symbol list, and returns the value  }{  of that constant in l. Returns TRUE if successfull, if not found,   }{  or if the constant is not of correct type, then returns FALSE       }{ Remarks: Also handle TRUE and FALSE returning in those cases 1 and 0 }{  respectively.                                                       }{**********************************************************************}var  srsym : tsym;  srsymtable : TSymtable;Begin  SearchIConstant:=false;{ check for TRUE or FALSE reserved words first }  if s = 'TRUE' then   Begin     SearchIConstant:=TRUE;     l:=1;     exit;   end;  if s = 'FALSE' then   Begin     SearchIConstant:=TRUE;     l:=0;     exit;   end;{ Check the constants in symtable }  asmsearchsym(s,srsym,srsymtable);  if srsym <> nil then   Begin     case srsym.typ of       constsym :         begin           if tconstsym(srsym).consttyp=constord then            Begin              l:=tconstsym(srsym).value.valueord.svalue;              SearchIConstant:=TRUE;              exit;            end;         end;       enumsym:         Begin           l:=tenumsym(srsym).value;           SearchIConstant:=TRUE;           exit;         end;       else         ;     end;   end;end;function AsmRegisterPara(sym: tabstractnormalvarsym): boolean;begin  result:=    (po_assembler in current_procinfo.procdef.procoptions) and    (sym.typ=paravarsym) and    (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REGISTER);end;Function GetRecordOffsetSize(s:string;out Offset: tcgint;out Size:tcgint; out mangledname: string; needvmtofs: boolean; out hastypecast: boolean):boolean;{ search and returns the offset and size of records/objects of the base }{ with field name setup in field.                              }{ returns FALSE if not found.                                  }{ used when base is a variable or a typed constant name.       }var  st   : TSymtable;  harrdef : tarraydef;  sym  : tsym;  srsymtable : TSymtable;  i    : longint;  base : string;  procdef: tprocdef;Begin  GetRecordOffsetSize:=FALSE;  Offset:=0;  Size:=0;  mangledname:='';  hastypecast:=false;  i:=pos('.',s);  if i=0 then   i:=255;  base:=Copy(s,1,i-1);  delete(s,1,i);  if base='SELF' then   st:=current_structdef.symtable  else   begin     asmsearchsym(base,sym,srsymtable);     { allow unitname.identifier }     if assigned(sym) and (sym.typ=unitsym) then       begin         i:=pos('.',s);         if i=0 then          i:=255;         base:=base+'.'+Copy(s,1,i-1);         delete(s,1,i);         asmsearchsym(base,sym,srsymtable);       end;     st:=nil;     { we can start with a var,type,typedconst }     if assigned(sym) then       case sym.typ of         staticvarsym,         localvarsym,         paravarsym :           st:=Tabstractvarsym(sym).vardef.GetSymtable(gs_record);         typesym :           st:=Ttypesym(sym).typedef.GetSymtable(gs_record);         else           ;       end     else       s:='';   end;  { now walk all recordsymtables }  while assigned(st) and (s<>'') do   begin     { load next field in base }     i:=pos('.',s);     if i=0 then      i:=255;     base:=Copy(s,1,i-1);     delete(s,1,i);     sym:=search_struct_member(tabstractrecorddef(st.defowner),base);     if not assigned(sym) then      begin        Message(asmr_e_unknown_field);        GetRecordOffsetSize:=false;        exit;      end;     st:=nil;     case sym.typ of       fieldvarsym :         with Tfieldvarsym(sym) do           begin             if not tabstractrecordsymtable(sym.owner).is_packed then               inc(Offset,fieldoffset)             else if tfieldvarsym(sym).fieldoffset mod 8 = 0 then               inc(Offset,fieldoffset div 8)             else               Message(asmr_e_packed_element);             size:=getsize;             case vardef.typ of               arraydef :                 begin                   { for arrays try to get the element size, take care of                     multiple indexes }                   harrdef:=tarraydef(vardef);                   while assigned(harrdef.elementdef) and                         (harrdef.elementdef.typ=arraydef) do                    harrdef:=tarraydef(harrdef.elementdef);                   if not is_packed_array(harrdef) then                     size:=harrdef.elesize                   else                     begin                       if (harrdef.elepackedbitsize mod 8) <> 0 then                         Message(asmr_e_packed_element);                       size := (harrdef.elepackedbitsize + 7) div 8;                     end;                 end;               recorddef :                 st:=trecorddef(vardef).symtable;               objectdef :                 st:=tobjectdef(vardef).symtable;               else                 ;             end;           end;       procsym:         begin           st:=nil;           if Tprocsym(sym).ProcdefList.Count>1 then             Message(asmr_w_calling_overload_func);           procdef:=tprocdef(tprocsym(sym).ProcdefList[0]);           if (not needvmtofs) then             begin               mangledname:=procdef.mangledname;             end           else             begin               { can only get the vmtoffset of virtual methods }               if not(po_virtualmethod in procdef.procoptions) or                   is_objectpascal_helper(procdef.struct) then                 Message1(asmr_e_no_vmtoffset_possible,FullTypeName(procdef,nil))               else                 begin                   { size = sizeof(target_system_pointer) }                   size:=sizeof(pint);                   offset:=tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber)                 end;             end;           { if something comes after the procsym, it's invalid assembler syntax }           GetRecordOffsetSize:=(s='');           exit;         end;       else         ;     end;   end;   { Support Field.Type as typecasting }   if (st=nil) and (s<>'') then     begin       asmsearchsym(s,sym,srsymtable);       if assigned(sym) and (sym.typ=typesym) then         begin           size:=ttypesym(sym).typedef.size;           s:='';           hastypecast:=true;         end;     end;   GetRecordOffsetSize:=(s='');end;Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;var  sym : tsym;  srsymtable : TSymtable;  hs  : string;Begin  hl:=nil;  SearchLabel:=false;{ Check for pascal labels, which are case insensetive }  hs:=upper(s);  asmsearchsym(hs,sym,srsymtable);  if sym=nil then   exit;  case sym.typ of    labelsym :      begin        if symtablestack.top.symtablelevel<>srsymtable.symtablelevel then          begin            Tlabelsym(sym).nonlocal:=true;            if emit then              include(current_procinfo.flags,pi_has_interproclabel);          end;        if not(assigned(tlabelsym(sym).asmblocklabel)) then          if Tlabelsym(sym).nonlocal then            current_asmdata.getglobaljumplabel(tlabelsym(sym).asmblocklabel)          else            current_asmdata.getjumplabel(tlabelsym(sym).asmblocklabel);        hl:=tlabelsym(sym).asmblocklabel;        if emit then          begin            if tlabelsym(sym).defined then              Message(sym_e_label_already_defined);            tlabelsym(sym).defined:=true;            hl.defined_in_asmstatement:=true          end        else          tlabelsym(sym).used:=true;        SearchLabel:=true;      end;    else      ;  end;end; {*************************************************************************} {                   Instruction Generation Utilities                      } {*************************************************************************}   Procedure ConcatString(p : TAsmList;s:string);  {*********************************************************************}  { PROCEDURE ConcatString(s:string);                                   }  {  Description: This routine adds the character chain pointed to in   }  {  s to the instruction linked list.                                  }  {*********************************************************************}  Begin     p.concat(Tai_string.Create(s));  end;Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);{*********************************************************************}{  Description: This routine adds the value constant to the current   }{  instruction linked list.                                           }{*********************************************************************}var  rangelo,rangehi : int64;Begin  case constsize of    1 :      begin        p.concat(Tai_const.Create_8bit(byte(value)));        rangelo:=low(shortint);        rangehi:=high(byte);      end;    2 :      begin        p.concat(Tai_const.Create_16bit(word(value)));        rangelo:=low(smallint);        rangehi:=high(word);      end;    4 :      begin        p.concat(Tai_const.Create_32bit(longint(value)));        rangelo:=low(longint);        rangehi:=high(cardinal);      end;    8 :      begin        p.concat(Tai_const.Create_64bit(int64(value)));        rangelo:=0;        rangehi:=0;      end;    else      internalerror(200405011);  end;  { check for out of bounds }  if (rangelo<>0) and     ((value>rangehi) or (value<rangelo)) then    Message(asmr_e_constant_out_of_bounds);end;  Procedure ConcatConstSymbol(p : TAsmList;const sym,endsym:string;symtyp:tasmsymtype;l:tcgint;constsize:byte;isofs:boolean);  begin{$ifdef i8086}    { 'DW xx' as well as 'DW OFFSET xx' are just near pointers }    if constsize=2 then      p.concat(Tai_const.Createname_near(sym,l))    else if constsize=4 then      begin        if isofs then          begin            { 'DD OFFSET xx' is a 32-bit offset; since we don't produce 32-bit              relocations yet, just do a 16-bit one and set the high word to 0 }            p.concat(Tai_const.Createname_near(sym,l));            p.concat(Tai_const.Create_16bit(0));          end        else          { 'DD xx' is a far pointer }          p.concat(Tai_const.Createname_far(sym,l));      end    else      internalerror(2018020701);{$else i8086}    p.concat(Tai_const.Createname(sym,l));{$endif i8086}  end;  Procedure ConcatRealConstant(p : TAsmList;value: bestreal; real_typ : tfloattype);  {***********************************************************************}  { PROCEDURE ConcatRealConstant(value: bestreal; real_typ : tfloattype); }  {  Description: This routine adds the value constant to the current     }  {  instruction linked list.                                             }  {   real_typ -> indicates the type of the real data to initialize:      }  {                  s32real -> create a single node.                     }  {                  s64real -> create a double node.                     }  {                  s80real -> create an extended node.                  }  {                  s64bit ->  create a  comp node.                      }  {                  f32bit ->  create a  fixed node. (not used normally) }  {***********************************************************************}    Begin       case real_typ of          s32real : p.concat(tai_realconst.create_s32real(value));          s64real :{$ifdef ARM}           if is_double_hilo_swapped then             p.concat(tai_realconst.create_s64real_hiloswapped(value))           else{$endif ARM}             p.concat(tai_realconst.create_s64real(value));          s80real : p.concat(tai_realconst.create_s80real(value,s80floattype.size));          sc80real : p.concat(tai_realconst.create_s80real(value,sc80floattype.size));          s64comp : p.concat(tai_realconst.create_s64compreal(trunc(value)));          else            internalerror(2014050608);       end;    end;   Procedure ConcatLabel(p: TAsmList;var l : tasmlabel);  {*********************************************************************}  { PROCEDURE ConcatLabel                                               }  {  Description: This routine either emits a label or a labeled        }  {  instruction to the linked list of instructions.                    }  {*********************************************************************}   begin     p.concat(Tai_label.Create(l));   end;   procedure ConcatAlign(p:TAsmList;l:tcgint);  {*********************************************************************}  { PROCEDURE ConcatPublic                                              }  {  Description: This routine emits an global   definition to the      }  {  linked list of instructions.(used by AT&T styled asm)              }  {*********************************************************************}   begin     p.concat(Tai_align.Create(l));   end;   procedure ConcatPublic(p:TAsmList;const s : string);  {*********************************************************************}  { PROCEDURE ConcatPublic                                              }  {  Description: This routine emits an global   definition to the      }  {  linked list of instructions.(used by AT&T styled asm)              }  {*********************************************************************}   begin       p.concat(Tai_symbol.Createname_global(s,AT_LABEL,0,voidcodepointertype));   end;   procedure ConcatLocal(p:TAsmList;const s : string);  {*********************************************************************}  { PROCEDURE ConcatLocal                                               }  {  Description: This routine emits an local    definition to the      }  {  linked list of instructions.                                       }  {*********************************************************************}   begin       p.concat(Tai_symbol.Createname(s,AT_LABEL,0,voidcodepointertype));   end;end.
 |