123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- {
- Copyright (c) 2019 by Jeppe Johansen
- Does the parsing for the LoongArch64 GNU AS styled inline assembler.
- 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 racpugas;
- {$I fpcdefs.inc}
- interface
- uses
- globtype,
- raatt,racpu,
- cpubase;
- const
- NRCalMax=64;
- type
- TArithOpers = (LLOR,LLAND,LINOR,LEXOR,LAND,LEQU,LUNE,LSLT,
- LBGT,LSLE,LBGE,LSL,LSR,LADD,LSUB,LMUL,LMOD,LDIV);
- TArithTreeType = (ATT_NUM,ATT_OP);
- TArithTree = record
- left : integer;
- right : integer;
- case typ:TArithTreeType of
- ATT_NUM : (num : tcgint);
- ATT_OP : (op : TArithOpers);
- end;
- TArrCals = array[1..NRCalMax] of TArithTree;
- TArrNums = array[1..(NRCalMax shr 1)] of tcgint;
- TArrAOps = array[1..(NRCalMax shr 1)] of TArithOpers;
- tloongarch64gasreader = class(tattreader)
- function is_register(const s: string):boolean;override;
- function is_asmopcode(const s: string):boolean;override;
- procedure handledollar;override;
- procedure handleopcode;override;
- procedure BuildOperand(oper : tloongarch64operand);
- procedure BuildOpCode(instr : tloongarch64instruction);
- function CalculateExprs(nr,first : tcgint; var nums : TArrNums; var ops : TArrAOps): tcgint;
- function BuildConstLA(from_question,cond : boolean): tcgint;
- function BuildSymLA(oper : tloongarch64operand; maybeconst: boolean): boolean;
- end;
- implementation
- uses
- { helpers }
- cutils,
- { global }
- globals,verbose,
- systems,
- { aasm }
- aasmbase,aasmtai,aasmdata,aasmcpu,
- { symtable }
- symconst,symsym,symdef,
- { parser }
- scanner,
- procinfo,
- rabase,rautils,
- cgbase,cgobj
- ;
- procedure tloongarch64gasreader.BuildOperand(oper: tloongarch64operand);
- var
- expr : string;
- typesize,l : TCGInt;
- tempreg : tregister;
- hl : tasmlabel;
- ofs : aint;
- refaddr: trefaddr;
- entered_paren: Boolean;
- Begin
- expr:='';
- entered_paren:=false;
- refaddr:=addr_no;
- { Although assembler has diverse ways to decode parameters,
- there are four normal ways to describe them.
- 1. Registers.
- 2. %addrtype(Symbol'addend'), addend means expression.
- 3. Symbol'addend'.
- 4. Else, expression. }
- case actasmtoken of
- AS_REGISTER:
- begin
- { save the type of register used. }
- tempreg:=actasmregister;
- Consume(AS_REGISTER);
- if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
- begin
- oper.opr.typ:=OPR_REGISTER;
- oper.opr.reg:=tempreg;
- end
- else
- Message(asmr_e_syn_operand);
- end;
- AS_MOD:
- begin
- Consume(AS_MOD);
- if actasmtoken<>AS_ID then
- Message(asmr_e_syntax_error);
- if lower(actasmpattern)='b16' then
- refaddr:=addr_b16
- else if lower(actasmpattern)='b21' then
- refaddr:=addr_b21
- else if lower(actasmpattern)='b26' then
- refaddr:=addr_b26
- else if lower(actasmpattern)='plt' then
- refaddr:=addr_plt
- else if lower(actasmpattern)='abs_hi20' then
- refaddr:=addr_abs_hi20
- else if lower(actasmpattern)='abs_lo12' then
- refaddr:=addr_abs_lo12
- else if lower(actasmpattern)='abs64_lo20' then
- refaddr:=addr_abs64_lo20
- else if lower(actasmpattern)='abs64_hi12' then
- refaddr:=addr_abs64_hi12
- else if lower(actasmpattern)='pc_hi20' then
- refaddr:=addr_pc_hi20
- else if lower(actasmpattern)='pc_lo12' then
- refaddr:=addr_pc_lo12
- else if lower(actasmpattern)='got_pc_hi20' then
- refaddr:=addr_got_pc_hi20
- else if lower(actasmpattern)='got_pc_lo12' then
- refaddr:=addr_got_pc_lo12
- else
- Message(asmr_e_syntax_error);
- Consume(AS_ID);
- if actasmtoken<>AS_LPAREN then
- Message(asmr_e_syntax_error);
- Consume(AS_LPAREN);
- BuildSymLA(oper,false);
- if actasmtoken<>AS_RPAREN then
- Message(asmr_e_syntax_error);
- Consume(AS_RPAREN);
- end;
- AS_DOT, AS_ID:
- begin
- if actopcode=A_LA_GOT then
- refaddr:=addr_pcrel
- else if actopcode=A_LA_ABS then
- refaddr:=addr_abs
- else
- refaddr:=addr_pcrel;
- if not BuildSymLA(oper,actasmtoken=AS_ID) then
- refaddr:=addr_no;
- end;
- AS_END,
- AS_SEPARATOR,
- AS_COMMA: ;
- else
- begin
- oper.opr.typ:=OPR_CONSTANT;
- oper.opr.val:=BuildConstLA(false,false);
- end;
- end; { end case }
- if refaddr<>addr_no then
- begin
- { Indirectly use parameter can be local and sym is paravarsym. }
- if oper.opr.typ=OPR_LOCAL then
- exit;
- if oper.opr.typ<>OPR_REFERENCE then
- oper.InitRef;
- oper.opr.ref.refaddr:=refaddr;
- end
- else if (oper.opr.typ=OPR_REFERENCE) and
- (oper.opr.ref.refaddr=addr_no) and
- assigned(oper.opr.ref.symbol) then
- oper.opr.ref.refaddr:=addr_pcrel;
- end;
- {*****************************************************************************
- tloongarch64gasreader
- *****************************************************************************}
- procedure tloongarch64gasreader.BuildOpCode(instr : tloongarch64instruction);
- var
- operandnum : longint;
- begin
- { opcode }
- if (actasmtoken<>AS_OPCODE) then
- begin
- Message(asmr_e_invalid_or_missing_opcode);
- RecoverConsume(true);
- exit;
- end;
- { Fill the instr object with the current state }
- with instr do
- begin
- Opcode:=ActOpcode;
- condition:=ActCondition;
- end;
- { We are reading operands, so opcode will be an AS_ID }
- operandnum:=1;
- Consume(AS_OPCODE);
- { Zero operand opcode ? }
- if actasmtoken in [AS_SEPARATOR,AS_END] then
- begin
- operandnum:=0;
- exit;
- end;
- { Read the operands }
- repeat
- case actasmtoken of
- AS_COMMA: { Operand delimiter }
- begin
- if operandnum>Max_Operands then
- Message(asmr_e_too_many_operands)
- else
- begin
- { condition operands doesn't set the operand but write to the
- condition field of the instruction
- }
- if instr.Operands[operandnum].opr.typ<>OPR_NONE then
- Inc(operandnum);
- end;
- Consume(AS_COMMA);
- end;
- AS_SEPARATOR,
- AS_END : { End of asm operands for this opcode }
- begin
- break;
- end;
- else
- BuildOperand(instr.Operands[operandnum] as tloongarch64operand);
- end; { end case }
- until false;
- if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
- dec(operandnum);
- instr.Ops:=operandnum;
- end;
- function tloongarch64gasreader.is_register(const s: string): boolean;
- var
- reg: TRegister;
- begin
- result:=inherited is_register(s);
- { reg found? search it in abinames? }
- if not(result) then
- begin
- reg:=is_extra_reg(s);
- if reg<>NR_NO then
- begin
- actasmregister:=reg;
- result:=true;
- actasmtoken:=AS_REGISTER;
- end;
- end;
- end;
- function tloongarch64gasreader.is_asmopcode(const s: string):boolean;
- var
- cond : tasmcond;
- hs, postfix : string;
- l: longint;
- begin
- { making s a value parameter would break other assembler readers }
- hs:=s;
- is_asmopcode:=false;
- { clear op code }
- actopcode:=A_None;
- { clear condition }
- fillchar(actcondition,sizeof(actcondition),0);
- { check for direction hint }
- actopcode := tasmop(ptruint(iasmops.find(hs)));
- if actopcode <> A_NONE then
- begin
- actasmtoken:=AS_OPCODE;
- is_asmopcode:=true;
- exit;
- end;
- end;
- procedure tloongarch64gasreader.handledollar;
- var
- len: longint;
- begin
- len:=1;
- actasmpattern[len]:='$';
- c:=current_scanner.asmgetchar;
- while c in ['A'..'Z','a'..'z','0'..'9'] do
- begin
- inc(len);
- actasmpattern[len]:=c;
- c:=current_scanner.asmgetchar;
- end;
- actasmpattern[0]:=chr(len);
- actasmpattern:=lower(actasmpattern);
- { TODO Something else. }
- if not is_register(actasmpattern) then
- internalerror(2022062915);
- end;
- procedure tloongarch64gasreader.handleopcode;
- var
- instr : tloongarch64instruction;
- begin
- instr:=tloongarch64instruction.create(tloongarch64operand);
- BuildOpCode(instr);
- { TODO insruction field }
- instr.ConcatInstruction(curlist);
- instr.Free;
- end;
- { In LoongArch binutils gas, the expression calculation is complex.
- The priority is ternary is the lowest and the unary is the highest.
- Ternary '?:', binary ordered by form low to high is '||', '&&',
- '|', '^', '&', '==,!=', '<,<=,>,>=', '<<,>>', '+,-' and '*,/,%',
- Unary is '+,-,~,!'. It is different form CalculateExpression, so
- we should implement ourselves. Collect integers and binary,
- calculate parentheses by recursing call, mark ternay and calculate
- unary in time. }
- function tloongarch64gasreader.CalculateExprs(nr,first : tcgint; var nums : TArrNums; var ops : TArrAOps): tcgint;
- procedure alloc_num(var idx : integer; var arr : TArrCals; num : int64);
- begin
- idx:=idx+1;
- if idx>NRCalMax then
- internalerror(2022081601);
- arr[idx].typ:=ATT_NUM;
- arr[idx].num:=num;
- end;
- procedure alloc_op(var idx : integer; var arr : TArrCals; op : TArithOpers);
- begin
- idx:=idx+1;
- if idx>NRCalMax then
- internalerror(2022081602);
- arr[idx].typ:=ATT_OP;
- arr[idx].op:=op;
- end;
- function priority_less(op1, op2 : TArithOpers): boolean;
- begin
- case op1 of
- LMUL,LMOD,LDIV:
- priority_less:=false;
- LADD,LSUB:
- priority_less:=op2 in [LMUL..LDIV];
- LSL,LSR:
- priority_less:=op2 in [LADD..LDIV];
- LSLT,LBGT,LSLE,LBGE:
- priority_less:=op2 in [LSL..LDIV];
- LEQU,LUNE:
- priority_less:=op2 in [LSLT..LDIV];
- LAND:
- priority_less:=op2 in [LEQU..LDIV];
- LEXOR:
- priority_less:=op2 in [LAND..LDIV];
- LINOR:
- priority_less:=op2 in [LEXOR..LDIV];
- LLAND:
- priority_less:=op2 in [LINOR..LDIV];
- LLOR:
- priority_less:=op2<>LLOR;
- end;
- end;
- function get_where_insert(head,item : integer; var arr : TArrCals) : integer;
- var
- last,t : integer;
- begin
- last:=0;
- t:=head;
- while arr[t].typ=ATT_OP do
- begin
- if priority_less(arr[item].op,arr[t].op) then
- break;
- last:=t;
- t:=arr[t].right;
- end;
- get_where_insert:=last;
- end;
- function arith_treecal(var arr : TArrCals; idx : integer): tcgint;
- var
- lv,rv : tcgint;
- begin
- if arr[idx].typ=ATT_NUM then
- begin
- result:=arr[idx].num;
- exit;
- end;
- if (arr[idx].left=0) and (arr[idx].right=0) then
- internalerror(2022081705);
- lv:=arith_treecal(arr,arr[idx].left);
- rv:=arith_treecal(arr,arr[idx].right);
- case arr[idx].op of
- LLOR: result:=tcgint((lv<>0) or (rv<>0));
- LLAND: result:=tcgint((lv<>0) and (rv<>0));
- LINOR: result:=lv or rv;
- LEXOR: result:=lv xor rv;
- LAND: result:=lv and rv;
- LEQU: result:=tcgint(lv=rv);
- LUNE: result:=tcgint(lv<>rv);
- LSLT: result:=tcgint(lv<rv);
- LBGT: result:=tcgint(lv>rv);
- LSLE: result:=tcgint(lv<=rv);
- LBGE: result:=tcgint(lv>=rv);
- LSL: result:=lv<<rv;
- LSR: result:=lv>>rv;
- LADD: result:=lv+rv;
- LSUB: result:=lv-rv;
- LMUL: result:=lv*rv;
- LMOD: result:=lv mod rv;
- LDIV: result:=lv div rv;
- end;
- end;
- procedure debug_treecal(var arr : TArrCals; idx : integer; first : boolean);
- const
- strops: Array[LLOR..LDIV] of string[3] =
- ('||','&&','|','^','&','==','!=','<','>',
- '<=','>=','<<','>>','+','-','*','%','/');
- begin
- if first then
- writeln('[Debug] ');
- if arr[idx].typ=ATT_NUM then
- begin
- write(arr[idx].num);
- exit;
- end;
- if (arr[idx].left=0) and (arr[idx].right=0) then
- writeln(#10,'[Debug Error]');
- debug_treecal(arr,arr[idx].left,false);
- if arr[idx].typ=ATT_OP then
- write(strops[arr[idx].op]);
- debug_treecal(arr,arr[idx].right,false);
- if first then
- writeln('=',arith_treecal(arr,idx));
- end;
- var
- i,curidx,curhead,curright,cursym,insidx : integer;
- exprs : TArrCals;
- begin
- if nr=0 then
- internalerror(2022081704);
- curidx:=0;
- alloc_num(curidx,exprs,first);
- curhead:=curidx;
- cursym:=0;
- for i := 1 to nr do
- begin
- alloc_op(curidx,exprs,ops[i]);
- cursym:=curidx;
- alloc_num(curidx,exprs,nums[i]);
- curright:=curidx;
- exprs[cursym].right:=curright;
- insidx:=get_where_insert(curhead,cursym,exprs);
- if insidx=0 then
- begin
- exprs[cursym].left:=curhead;
- curhead:=cursym;
- end
- else
- begin
- exprs[cursym].left:=exprs[insidx].right;
- exprs[insidx].right:=cursym;
- end;
- end;
- { debug_treecal(exprs,curhead,true); }
- result:=arith_treecal(exprs,curhead);
- end;
- function tloongarch64gasreader.BuildConstLA(from_question,cond : boolean): tcgint;
- function get_a_int: tcgint;
- var
- l : tcgint;
- begin
- result:=0;
- case actasmtoken of
- AS_PLUS:
- begin
- Consume(AS_PLUS);
- result:=get_a_int();
- end;
- AS_MINUS:
- begin
- Consume(AS_MINUS);
- result:=-get_a_int();
- end;
- AS_NOT:
- begin
- Consume(AS_NOT);
- result:=tcgint(get_a_int()=0);
- end;
- AS_NOR:
- begin
- Consume(AS_NOR);
- result:=not get_a_int();
- end;
- AS_ID:
- begin
- if SearchIConstant(actasmpattern,l) then
- result:=l
- else
- internalerror(2022081101);
- Consume(AS_ID);
- end;
- AS_INTNUM:
- begin
- result:=CalculateExpression(actasmpattern);
- Consume(AS_INTNUM);
- end;
- AS_LPAREN:
- begin
- Consume(AS_LPAREN);
- l:=BuildConstLA(false,false);
- if actasmtoken<>AS_RPAREN then
- Message(asmr_e_syntax_error);
- Consume(AS_RPAREN);
- result:=l;
- end;
- else
- Message(asmr_e_syntax_error);
- end;
- end;
- function get_a_op: TArithOpers;
- begin
- result:=LADD; { As initialized }
- case actasmtoken of
- AS_SHL:
- begin
- Consume(AS_SHL);
- result:=LSL;
- end;
- AS_SHR:
- begin
- Consume(AS_SHR);
- result:=LSR;
- end;
- AS_LT:
- begin
- Consume(AS_LT);
- if actasmtoken=AS_EQUAL then
- begin
- Consume(AS_EQUAL);
- result:=LSLE;
- end
- else
- result:=LSLT;
- end;
- AS_GT:
- begin
- Consume(AS_GT);
- if actasmtoken=AS_EQUAL then
- begin
- Consume(AS_EQUAL);
- result:=LBGE;
- end
- else
- result:=LBGT;
- end;
- AS_OR:
- begin
- Consume(AS_OR);
- if actasmtoken=AS_OR then
- begin
- Consume(AS_OR);
- result:=LLOR;
- end
- else
- result:=LINOR;
- end;
- AS_AND:
- begin
- Consume(AS_AND);
- if actasmtoken=AS_AND then
- begin
- Consume(AS_AND);
- result:=LLAND;
- end
- else
- result:=LAND;
- end;
- AS_EQUAL:
- begin
- Consume(AS_EQUAL);
- if actasmtoken<>AS_EQUAL then
- internalerror(2022081701);
- Consume(AS_EQUAL);
- result:=LEQU;
- end;
- AS_NOT:
- begin
- Consume(AS_NOT);
- if actasmtoken<>AS_EQUAL then
- internalerror(2022081702);
- Consume(AS_EQUAL);
- result:=LUNE;
- end;
- AS_XOR:
- begin
- Consume(AS_XOR);
- result:=LEXOR;
- end;
- AS_PLUS:
- begin
- Consume(AS_PLUS);
- result:=LADD;
- end;
- AS_MINUS:
- begin
- Consume(AS_MINUS);
- result:=LSUB;
- end;
- AS_STAR:
- begin
- Consume(AS_STAR);
- result:=LMUL;
- end;
- AS_MOD:
- begin
- Consume(AS_MOD);
- result:=LMOD;
- end;
- AS_SLASH:
- begin
- Consume(AS_SLASH);
- result:=LDIV;
- end;
- else
- Message(asmr_e_syntax_error);
- end;
- end;
- var
- firstnum,nr,l,l2 : tcgint;
- IntStack : TArrNums;
- OpsStack : TArrAOps;
- op_or_int: boolean;
- begin
- result:=0;
- nr:=0;
- firstnum:=get_a_int;
- { Most of case will return as they only have an integer. }
- repeat
- case actasmtoken of
- AS_END,AS_SEPARATOR,AS_COMMA,AS_RPAREN: break;
- AS_LPAREN:
- begin
- Consume(AS_LPAREN);
- l:=BuildConstLA(false,false);
- if actasmtoken<>AS_RPAREN then
- Message(asmr_e_syntax_error);
- Consume(AS_RPAREN);
- end;
- AS_QUESTION:
- begin
- Consume(AS_QUESTION);
- if nr=0 then
- l:=firstnum
- else
- l:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
- result:=BuildConstLA(true,l<>0);
- exit;
- end;
- AS_COLON:
- begin
- if not from_question then
- Message(asmr_e_syntax_error);
- Consume(AS_COLON);
- if nr=0 then
- l:=firstnum
- else
- l:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
- l2:=BuildConstLA(false,false);
- if cond then
- result:=l
- else
- result:=l2;
- exit;
- end;
- else
- begin
- nr:=nr+1;
- if nr>(NRCalMax shr 1) then
- internalerror(2022081703);
- OpsStack[nr]:=get_a_op;
- IntStack[nr]:=get_a_int;
- end;
- end; { case actasmtoken }
- until false;
- if nr=0 then
- result:=firstnum
- else
- result:=CalculateExprs(nr,firstnum,IntStack,OpsStack);
- end;
- function tloongarch64gasreader.BuildSymLA(oper : tloongarch64operand; maybeconst : boolean): boolean;
- var
- hl : tasmlabel;
- value : tcgint;
- toffset, tsize: tcgint;
- expr,mangledname: string;
- begin
- result:=True;
- if (is_locallabel(actasmpattern)) then
- begin
- CreateLocalLabel(actasmpattern,hl,false);
- Consume(AS_ID);
- oper.InitRef;
- oper.opr.ref.symbol:=hl;
- end
- else if SearchLabel(actasmpattern,hl,false) then
- begin
- Consume(AS_ID);
- oper.InitRef;
- oper.opr.ref.symbol:=hl;
- end
- else if maybeconst then
- begin
- if not SearchIConstant(actasmpattern,value) then
- begin
- expr:=actasmpattern;
- Consume(AS_ID);
- if actasmtoken = AS_DOT then
- begin
- mangledname:='';
- BuildRecordOffsetSize(expr, toffset, tsize, mangledname, false);
- if mangledname <> '' then
- Message(asmr_e_wrong_sym_type);
- oper.opr.typ:=OPR_CONSTANT;
- oper.opr.val:=toffset;
- Result:=False;
- end
- else
- begin
- oper.InitRef;
- oper.SetupVar(expr,false);
- end;
- end;
- end
- else if actasmtoken=AS_ID then
- begin
- oper.InitRef;
- oper.SetupVar(actasmpattern,false);
- Consume(AS_ID);
- end
- else
- begin
- Message(asmr_e_syntax_error);
- internalerror(2022082501);
- end;
- if actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA,AS_RPAREN] then
- exit;
- value:=BuildConstLA(false,false);
- if assigned(oper.opr.ref.symbol) then
- oper.opr.ref.offset:=value
- else
- begin
- oper.opr.typ:=OPR_CONSTANT;
- oper.opr.val:=value;
- Result:=False;
- end;
- end;
- {*****************************************************************************
- Initialize
- *****************************************************************************}
- const
- asmmode_loongarch64_standard_info : tasmmodeinfo =
- (
- id : asmmode_standard;
- idtxt : 'STANDARD';
- casmreader : tloongarch64gasreader;
- );
- initialization
- RegisterAsmMode(asmmode_loongarch64_standard_info);
- end.
|