diff options
author | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-10-20 19:20:38 +0000 |
---|---|---|
committer | peter <peter@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-10-20 19:20:38 +0000 |
commit | 5ed980d600661e3e77f429a510f093f4a001dee9 (patch) | |
tree | 40d655e7921c1019d039da654a9df550de3cd249 /compiler/sparc | |
parent | 907c764cb881dab769452696fc5e6bee076c2656 (diff) | |
download | fpc-5ed980d600661e3e77f429a510f093f4a001dee9.tar.gz |
* retag for unitrwunitrw
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/unitrw@1551 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler/sparc')
35 files changed, 7110 insertions, 0 deletions
diff --git a/compiler/sparc/aasmcpu.pas b/compiler/sparc/aasmcpu.pas new file mode 100644 index 0000000000..556e060d11 --- /dev/null +++ b/compiler/sparc/aasmcpu.pas @@ -0,0 +1,312 @@ +{ + Copyright (c) 1999-2002 by Mazen Neifer + + Contains the assembler object for the SPARC + + 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 aasmcpu; + +{$i fpcdefs.inc} + +interface + +uses + cclasses, + globtype,globals,verbose, + aasmbase,aasmtai, + cgbase,cgutils,cpubase,cpuinfo; + + const + { "mov reg,reg" source operand number } + O_MOV_SOURCE = 0; + { "mov reg,reg" source operand number } + O_MOV_DEST = 1; + + type + taicpu = class(tai_cpu_abstract) + delayslot_annulled : boolean; { conditinal opcode with ,a } + constructor op_none(op : tasmop); + + constructor op_reg(op : tasmop;_op1 : tregister); + constructor op_const(op : tasmop;_op1 : LongInt); + constructor op_ref(op : tasmop;const _op1 : treference); + + constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister); + constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); + constructor op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt); + constructor op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister); + constructor op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister); + + constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); + constructor op_reg_ref_reg(op:tasmop;_op1:TRegister;_op2:TReference;_op3:tregister); + constructor op_reg_const_reg(op:tasmop;_op1:TRegister;_op2:aint;_op3:tregister); + + { this is for Jmp instructions } + constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); + constructor op_sym(op : tasmop;_op1 : tasmsymbol); + constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); + procedure loadbool(opidx:longint;_b:boolean); + { register allocation } + function is_same_reg_move(regtype: Tregistertype):boolean; override; + + { register spilling code } + function spilling_get_operation_type(opnr: longint): topertype;override; + end; + + tai_align = class(tai_align_abstract) + { nothing to add } + end; + + procedure InitAsm; + procedure DoneAsm; + + function spilling_create_load(const ref:treference;r:tregister): tai; + function spilling_create_store(r:tregister; const ref:treference): tai; + +implementation + +{***************************************************************************** + taicpu Constructors +*****************************************************************************} + + procedure taicpu.loadbool(opidx:longint;_b:boolean); + begin + if opidx>=ops then + ops:=opidx+1; + with oper[opidx]^ do + begin + if typ=top_ref then + dispose(ref); + b:=_b; + typ:=top_bool; + end; + end; + + + constructor taicpu.op_none(op : tasmop); + begin + inherited create(op); + end; + + + constructor taicpu.op_reg(op : tasmop;_op1 : tregister); + begin + inherited create(op); + ops:=1; + loadreg(0,_op1); + end; + + + constructor taicpu.op_ref(op : tasmop;const _op1 : treference); + begin + inherited create(op); + ops:=1; + loadref(0,_op1); + end; + + + constructor taicpu.op_const(op : tasmop;_op1 : LongInt); + begin + inherited create(op); + ops:=1; + loadconst(0,_op1); + end; + + + constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister); + begin + inherited create(op); + ops:=2; + loadreg(0,_op1); + loadreg(1,_op2); + end; + + constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt); + begin + inherited create(op); + ops:=2; + loadreg(0,_op1); + loadconst(1,_op2); + end; + + constructor taicpu.op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister); + begin + inherited create(op); + ops:=2; + loadconst(0,_op1); + loadreg(1,_op2); + end; + + + constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); + begin + inherited create(op); + ops:=2; + loadreg(0,_op1); + loadref(1,_op2); + end; + + + constructor taicpu.op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister); + begin + inherited create(op); + ops:=2; + loadref(0,_op1); + loadreg(1,_op2); + end; + + + constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); + begin + inherited create(op); + ops:=3; + loadreg(0,_op1); + loadreg(1,_op2); + loadreg(2,_op3); + end; + + + constructor taicpu.op_reg_ref_reg(op:tasmop;_op1:TRegister;_op2:TReference;_op3:tregister); + begin + inherited create(op); + { only allowed to load the address } + if not(_op2.refaddr in [addr_lo,addr_hi]) then + internalerror(200305311); + ops:=3; + loadreg(0,_op1); + loadref(1,_op2); + loadreg(2,_op3); + end; + + + constructor taicpu.op_reg_const_reg(op:tasmop;_op1:TRegister;_op2:aint;_op3:tregister); + begin + inherited create(op); + ops:=3; + loadreg(0,_op1); + loadconst(1,_op2); + loadreg(2,_op3); + end; + + + constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); + begin + inherited create(op); + is_jmp:=op in [A_BA,A_Bxx]; + condition:=cond; + ops:=1; + loadsymbol(0,_op1,0); + end; + + + constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol); + begin + inherited create(op); + is_jmp:=op in [A_BA,A_Bxx]; + ops:=1; + loadsymbol(0,_op1,0); + end; + + + constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint); + begin + inherited create(op); + ops:=1; + loadsymbol(0,_op1,_op1ofs); + end; + + + function taicpu.is_same_reg_move(regtype: Tregistertype):boolean; + begin + result:=( + ((opcode=A_MOV) and (regtype = R_INTREGISTER)) or + ((regtype = R_FPUREGISTER) and (opcode in [A_FMOVS,A_FMOVD])) + ) and + (ops=2) and + (oper[0]^.typ=top_reg) and + (oper[1]^.typ=top_reg) and + (oper[0]^.reg=oper[1]^.reg); + end; + + + function taicpu.spilling_get_operation_type(opnr: longint): topertype; + begin + if opnr=ops-1 then + result := operand_write + else + result := operand_read; + end; + + + function spilling_create_load(const ref:treference;r:tregister): tai; + begin + case getregtype(r) of + R_INTREGISTER : + result:=taicpu.op_ref_reg(A_LD,ref,r); + R_FPUREGISTER : + begin + case getsubreg(r) of + R_SUBFS : + result:=taicpu.op_ref_reg(A_LDF,ref,r); + R_SUBFD : + result:=taicpu.op_ref_reg(A_LDD,ref,r); + else + internalerror(200401042); + end; + end + else + internalerror(200401041); + end; + end; + + + function spilling_create_store(r:tregister; const ref:treference): tai; + begin + case getregtype(r) of + R_INTREGISTER : + result:=taicpu.op_reg_ref(A_ST,r,ref); + R_FPUREGISTER : + begin + case getsubreg(r) of + R_SUBFS : + result:=taicpu.op_reg_ref(A_STF,r,ref); + R_SUBFD : + result:=taicpu.op_reg_ref(A_STD,r,ref); + else + internalerror(200401042); + end; + end + else + internalerror(200401041); + end; + end; + + + procedure InitAsm; + begin + end; + + + procedure DoneAsm; + begin + end; + +begin + cai_cpu:=taicpu; + cai_align:=tai_align; +end. diff --git a/compiler/sparc/aoptcpu.pas b/compiler/sparc/aoptcpu.pas new file mode 100644 index 0000000000..cb656af36e --- /dev/null +++ b/compiler/sparc/aoptcpu.pas @@ -0,0 +1,41 @@ +{ + Copyright (c) 1998-2004 by Jonas Maebe + + This unit calls the optimization procedures to optimize the assembler + code for sparc + + 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 aoptcpu; + +{$i fpcdefs.inc} + + Interface + + uses + cpubase, aoptobj, aoptcpub, aopt; + + Type + TCpuAsmOptimizer = class(TAsmOptimizer) + End; + + Implementation + +begin + casmoptimizer:=TCpuAsmOptimizer; +end. diff --git a/compiler/sparc/aoptcpub.pas b/compiler/sparc/aoptcpub.pas new file mode 100644 index 0000000000..b6954875a2 --- /dev/null +++ b/compiler/sparc/aoptcpub.pas @@ -0,0 +1,120 @@ + { + Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal + Development Team + + This unit contains several types and constants necessary for the + optimizer to work on the sparc architecture + + 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 aoptcpub; { Assembler OPTimizer CPU specific Base } + +{$i fpcdefs.inc} + +{ enable the following define if memory references can have both a base and } +{ index register in 1 operand } + +{$define RefsHaveIndexReg} + +{ enable the following define if memory references can have a scaled index } + +{ define RefsHaveScale} + +{ enable the following define if memory references can have a segment } +{ override } + +{ define RefsHaveSegment} + +Interface + +Uses + cpubase,aasmcpu,AOptBase; + +Type + +{ type of a normal instruction } + TInstr = Taicpu; + PInstr = ^TInstr; + +{ ************************************************************************* } +{ **************************** TCondRegs ********************************** } +{ ************************************************************************* } +{ Info about the conditional registers } + TCondRegs = Object + Constructor Init; + Destructor Done; + End; + +{ ************************************************************************* } +{ **************************** TAoptBaseCpu ******************************* } +{ ************************************************************************* } + + TAoptBaseCpu = class(TAoptBase) + End; + + +{ ************************************************************************* } +{ ******************************* Constants ******************************* } +{ ************************************************************************* } +Const + +{ the maximum number of things (registers, memory, ...) a single instruction } +{ changes } + + MaxCh = 3; + +{ the maximum number of operands an instruction has } + + MaxOps = 3; + +{Oper index of operand that contains the source (reference) with a load } +{instruction } + + LoadSrc = 0; + +{Oper index of operand that contains the destination (register) with a load } +{instruction } + + LoadDst = 1; + +{Oper index of operand that contains the source (register) with a store } +{instruction } + + StoreSrc = 0; + +{Oper index of operand that contains the destination (reference) with a load } +{instruction } + + StoreDst = 1; + + aopt_uncondjmp = A_BA; + aopt_condjmp = A_Bxx; + +Implementation + +{ ************************************************************************* } +{ **************************** TCondRegs ********************************** } +{ ************************************************************************* } +Constructor TCondRegs.init; +Begin +End; + +Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl} +Begin +End; + +End. diff --git a/compiler/sparc/aoptcpud.pas b/compiler/sparc/aoptcpud.pas new file mode 100644 index 0000000000..cb8c5d319f --- /dev/null +++ b/compiler/sparc/aoptcpud.pas @@ -0,0 +1,36 @@ +{ + Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal + Development Team + + 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 aoptcpud; + +{$i fpcdefs.inc} + + interface + + uses + aoptda; + + type + TAOptDFACpu = class(TAOptDFA) + end; + + implementation + +end. diff --git a/compiler/sparc/cgcpu.pas b/compiler/sparc/cgcpu.pas new file mode 100644 index 0000000000..593f936d66 --- /dev/null +++ b/compiler/sparc/cgcpu.pas @@ -0,0 +1,1479 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + This unit implements the code generator for the SPARC + + 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 cgcpu; + +{$i fpcdefs.inc} + +interface + + uses + globtype,parabase, + cgbase,cgutils,cgobj,cg64f32, + aasmbase,aasmtai,aasmcpu, + cpubase,cpuinfo, + node,symconst,SymType,symdef, + rgcpu; + + type + TCgSparc=class(tcg) + protected + function IsSimpleRef(const ref:treference):boolean; + public + procedure init_register_allocators;override; + procedure done_register_allocators;override; + function getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;override; + { sparc special, needed by cg64 } + procedure make_simple_ref(list:taasmoutput;var ref: treference); + procedure handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference); + procedure handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aint;dst:tregister); + { parameter } + procedure a_param_const(list:TAasmOutput;size:tcgsize;a:aint;const paraloc:TCGPara);override; + procedure a_param_ref(list:TAasmOutput;sz:tcgsize;const r:TReference;const paraloc:TCGPara);override; + procedure a_paramaddr_ref(list:TAasmOutput;const r:TReference;const paraloc:TCGPara);override; + procedure a_paramfpu_reg(list : taasmoutput;size : tcgsize;const r : tregister;const paraloc : TCGPara);override; + procedure a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);override; + procedure a_call_name(list:TAasmOutput;const s:string);override; + procedure a_call_reg(list:TAasmOutput;Reg:TRegister);override; + { General purpose instructions } + procedure a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:aint;reg:TRegister);override; + procedure a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister);override; + procedure a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aint;src, dst:tregister);override; + procedure a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister);override; + procedure a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override; + procedure a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override; + { move instructions } + procedure a_load_const_reg(list:TAasmOutput;size:tcgsize;a:aint;reg:tregister);override; + procedure a_load_const_ref(list:TAasmOutput;size:tcgsize;a:aint;const ref:TReference);override; + procedure a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCgSize;reg:TRegister;const ref:TReference);override; + procedure a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister);override; + procedure a_load_reg_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;reg1,reg2:tregister);override; + procedure a_loadaddr_ref_reg(list:TAasmOutput;const ref:TReference;r:tregister);override; + { fpu move instructions } + procedure a_loadfpu_reg_reg(list:TAasmOutput;size:tcgsize;reg1, reg2:tregister);override; + procedure a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister);override; + procedure a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference);override; + { comparison operations } + procedure a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aint;reg:tregister;l:tasmlabel);override; + procedure a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel);override; + procedure a_jmp_always(List:TAasmOutput;l:TAsmLabel);override; + procedure a_jmp_name(list : taasmoutput;const s : string);override; + procedure a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:tasmlabel);{ override;} + procedure a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel);override; + procedure g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister);override; + procedure g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef);override; + procedure g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);override; + procedure g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);override; + procedure g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean);override; + procedure g_restore_standard_registers(list:taasmoutput);override; + procedure g_save_standard_registers(list : taasmoutput);override; + procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);override; + procedure g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);override; + procedure g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint); + procedure g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override; + end; + + TCg64Sparc=class(tcg64f32) + private + procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean); + public + procedure a_load64_reg_ref(list : taasmoutput;reg : tregister64;const ref : treference);override; + procedure a_load64_ref_reg(list : taasmoutput;const ref : treference;reg : tregister64);override; + procedure a_param64_ref(list : taasmoutput;const r : treference;const paraloc : tcgpara);override; + procedure a_op64_reg_reg(list:TAasmOutput;op:TOpCG;size : tcgsize;regsrc,regdst:TRegister64);override; + procedure a_op64_const_reg(list:TAasmOutput;op:TOpCG;size : tcgsize;value:int64;regdst:TRegister64);override; + procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override; + procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override; + procedure a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override; + procedure a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override; + end; + + const + TOpCG2AsmOp : array[topcg] of TAsmOp=( + A_NONE,A_ADD,A_AND,A_UDIV,A_SDIV,A_SMUL,A_UMUL,A_NEG,A_NOT,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR + ); + TOpCG2AsmOpWithFlags : array[topcg] of TAsmOp=( + A_NONE,A_ADDcc,A_ANDcc,A_UDIVcc,A_SDIVcc,A_SMULcc,A_UMULcc,A_NEG,A_NOT,A_ORcc,A_SRA,A_SLL,A_SRL,A_SUBcc,A_XORcc + ); + TOpCmp2AsmCond : array[topcmp] of TAsmCond=(C_NONE, + C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A + ); + + +implementation + + uses + globals,verbose,systems,cutils, + paramgr,fmodule, + tgobj, + procinfo,cpupi; + + + function TCgSparc.IsSimpleRef(const ref:treference):boolean; + begin + if (ref.base=NR_NO) and (ref.index<>NR_NO) then + InternalError(2002100804); + result :=not(assigned(ref.symbol))and + (((ref.index = NR_NO) and + (ref.offset >= simm13lo) and + (ref.offset <= simm13hi)) or + ((ref.index <> NR_NO) and + (ref.offset = 0))); + end; + + + procedure tcgsparc.make_simple_ref(list:taasmoutput;var ref: treference); + var + tmpreg : tregister; + tmpref : treference; + begin + tmpreg:=NR_NO; + { Be sure to have a base register } + if (ref.base=NR_NO) then + begin + ref.base:=ref.index; + ref.index:=NR_NO; + end; + if (cs_create_pic in aktmoduleswitches) and + assigned(ref.symbol) then + begin + tmpreg:=GetIntRegister(list,OS_INT); + reference_reset(tmpref); + tmpref.symbol:=ref.symbol; + tmpref.refaddr:=addr_pic; + if not(pi_needs_got in current_procinfo.flags) then + internalerror(200501161); + tmpref.index:=current_procinfo.got; + list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg)); + ref.symbol:=nil; + if (ref.index<>NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg)); + ref.index:=tmpreg; + end + else + begin + if ref.base<>NR_NO then + ref.index:=tmpreg + else + ref.base:=tmpreg; + end; + end; + { When need to use SETHI, do it first } + if assigned(ref.symbol) or + (ref.offset<simm13lo) or + (ref.offset>simm13hi) then + begin + tmpreg:=GetIntRegister(list,OS_INT); + reference_reset(tmpref); + tmpref.symbol:=ref.symbol; + tmpref.offset:=ref.offset; + tmpref.refaddr:=addr_hi; + list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg)); + if (ref.offset=0) and (ref.index=NR_NO) and + (ref.base=NR_NO) then + begin + ref.refaddr:=addr_lo; + end + else + begin + { Load the low part is left } + tmpref.refaddr:=addr_lo; + list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg)); + ref.offset:=0; + { symbol is loaded } + ref.symbol:=nil; + end; + if (ref.index<>NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg)); + ref.index:=tmpreg; + end + else + begin + if ref.base<>NR_NO then + ref.index:=tmpreg + else + ref.base:=tmpreg; + end; + end; + if (ref.base<>NR_NO) then + begin + if (ref.index<>NR_NO) and + ((ref.offset<>0) or assigned(ref.symbol)) then + begin + if tmpreg=NR_NO then + tmpreg:=GetIntRegister(list,OS_INT); + list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg)); + ref.base:=tmpreg; + ref.index:=NR_NO; + end; + end; + end; + + + procedure tcgsparc.handle_load_store(list:taasmoutput;isstore:boolean;op: tasmop;reg:tregister;ref: treference); + begin + make_simple_ref(list,ref); + if isstore then + list.concat(taicpu.op_reg_ref(op,reg,ref)) + else + list.concat(taicpu.op_ref_reg(op,ref,reg)); + end; + + + procedure tcgsparc.handle_reg_const_reg(list:taasmoutput;op:Tasmop;src:tregister;a:aint;dst:tregister); + var + tmpreg : tregister; + begin + if (a<simm13lo) or + (a>simm13hi) then + begin + tmpreg:=GetIntRegister(list,OS_INT); + a_load_const_reg(list,OS_INT,a,tmpreg); + list.concat(taicpu.op_reg_reg_reg(op,src,tmpreg,dst)); + end + else + list.concat(taicpu.op_reg_const_reg(op,src,a,dst)); + end; + + +{**************************************************************************** + Assembler code +****************************************************************************} + + procedure Tcgsparc.init_register_allocators; + begin + inherited init_register_allocators; + + if (cs_create_pic in aktmoduleswitches) and + (pi_needs_got in current_procinfo.flags) then + begin + current_procinfo.got:=NR_L7; + rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD, + [RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5, + RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6], + first_int_imreg,[]); + end + else + rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD, + [RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5, + RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6,RS_L7], + first_int_imreg,[]); + + rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBFS, + [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7, + RS_F8,RS_F9,RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15, + RS_F16,RS_F17,RS_F18,RS_F19,RS_F20,RS_F21,RS_F22,RS_F23, + RS_F24,RS_F25,RS_F26,RS_F27,RS_F28,RS_F29,RS_F30,RS_F31], + first_fpu_imreg,[]); + end; + + + procedure Tcgsparc.done_register_allocators; + begin + rg[R_INTREGISTER].free; + rg[R_FPUREGISTER].free; + inherited done_register_allocators; + end; + + + function tcgsparc.getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister; + begin + if size=OS_F64 then + result:=rg[R_FPUREGISTER].getregister(list,R_SUBFD) + else + result:=rg[R_FPUREGISTER].getregister(list,R_SUBFS); + end; + + + procedure TCgSparc.a_param_const(list:TAasmOutput;size:tcgsize;a:aint;const paraloc:TCGPara); + var + Ref:TReference; + begin + paraloc.check_simple_location; + case paraloc.location^.loc of + LOC_REGISTER,LOC_CREGISTER: + a_load_const_reg(list,size,a,paraloc.location^.register); + LOC_REFERENCE: + begin + { Code conventions need the parameters being allocated in %o6+92 } + with paraloc.location^.Reference do + begin + if (Index=NR_SP) and (Offset<Target_info.first_parm_offset) then + InternalError(2002081104); + reference_reset_base(ref,index,offset); + end; + a_load_const_ref(list,size,a,ref); + end; + else + InternalError(2002122200); + end; + end; + + + procedure TCgSparc.a_param_ref(list:TAasmOutput;sz:TCgSize;const r:TReference;const paraloc:TCGPara); + var + ref: treference; + tmpreg:TRegister; + begin + paraloc.check_simple_location; + with paraloc.location^ do + begin + case loc of + LOC_REGISTER,LOC_CREGISTER : + a_load_ref_reg(list,sz,sz,r,Register); + LOC_REFERENCE: + begin + { Code conventions need the parameters being allocated in %o6+92 } + with Reference do + begin + if (Index=NR_SP) and (Offset<Target_info.first_parm_offset) then + InternalError(2002081104); + reference_reset_base(ref,index,offset); + end; + tmpreg:=GetIntRegister(list,OS_INT); + a_load_ref_reg(list,sz,sz,r,tmpreg); + a_load_reg_ref(list,sz,sz,tmpreg,ref); + end; + else + internalerror(2002081103); + end; + end; + end; + + + procedure TCgSparc.a_paramaddr_ref(list:TAasmOutput;const r:TReference;const paraloc:TCGPara); + var + Ref:TReference; + TmpReg:TRegister; + begin + paraloc.check_simple_location; + with paraloc.location^ do + begin + case loc of + LOC_REGISTER,LOC_CREGISTER: + a_loadaddr_ref_reg(list,r,register); + LOC_REFERENCE: + begin + reference_reset(ref); + ref.base := reference.index; + ref.offset := reference.offset; + tmpreg:=GetAddressRegister(list); + a_loadaddr_ref_reg(list,r,tmpreg); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref); + end; + else + internalerror(2002080701); + end; + end; + end; + + + procedure tcgsparc.a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara); + var + href,href2 : treference; + hloc : pcgparalocation; + begin + href:=ref; + hloc:=paraloc.location; + while assigned(hloc) do + begin + case hloc^.loc of + LOC_REGISTER : + a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register); + LOC_REFERENCE : + begin + reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset); + a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2); + end; + else + internalerror(200408241); + end; + inc(href.offset,tcgsize2size[hloc^.size]); + hloc:=hloc^.next; + end; + end; + + + procedure tcgsparc.a_paramfpu_reg(list : taasmoutput;size : tcgsize;const r : tregister;const paraloc : TCGPara); + var + href : treference; + begin + tg.GetTemp(list,TCGSize2Size[size],tt_normal,href); + a_loadfpu_reg_ref(list,size,r,href); + a_paramfpu_ref(list,size,href,paraloc); + tg.Ungettemp(list,href); + end; + + + procedure TCgSparc.a_call_name(list:TAasmOutput;const s:string); + begin + list.concat(taicpu.op_sym(A_CALL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION))); + { Delay slot } + list.concat(taicpu.op_none(A_NOP)); + end; + + + procedure TCgSparc.a_call_reg(list:TAasmOutput;Reg:TRegister); + begin + list.concat(taicpu.op_reg(A_CALL,reg)); + { Delay slot } + list.concat(taicpu.op_none(A_NOP)); + end; + + + {********************** load instructions ********************} + + procedure TCgSparc.a_load_const_reg(list : TAasmOutput;size : TCGSize;a : aint;reg : TRegister); + begin + { we don't use the set instruction here because it could be evalutated to two + instructions which would cause problems with the delay slot (FK) } + if (a=0) then + list.concat(taicpu.op_reg(A_CLR,reg)) + { sethi allows to set the upper 22 bit, so we'll take full advantage of it } + else if (a and aint($1fff))=0 then + list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg)) + else if (a>=simm13lo) and (a<=simm13hi) then + list.concat(taicpu.op_const_reg(A_MOV,a,reg)) + else + begin + list.concat(taicpu.op_const_reg(A_SETHI,a shr 10,reg)); + list.concat(taicpu.op_reg_const_reg(A_OR,reg,a and aint($3ff),reg)); + end; + end; + + + procedure TCgSparc.a_load_const_ref(list : TAasmOutput;size : tcgsize;a : aint;const ref : TReference); + begin + if a=0 then + a_load_reg_ref(list,size,size,NR_G0,ref) + else + inherited a_load_const_ref(list,size,a,ref); + end; + + + procedure TCgSparc.a_load_reg_ref(list:TAasmOutput;FromSize,ToSize:TCGSize;reg:tregister;const Ref:TReference); + var + op : tasmop; + begin + if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then + fromsize := tosize; + case fromsize of + { signed integer registers } + OS_8, + OS_S8: + Op:=A_STB; + OS_16, + OS_S16: + Op:=A_STH; + OS_32, + OS_S32: + Op:=A_ST; + else + InternalError(2002122100); + end; + handle_load_store(list,true,op,reg,ref); + end; + + + procedure TCgSparc.a_load_ref_reg(list:TAasmOutput;FromSize,ToSize:TCgSize;const ref:TReference;reg:tregister); + var + op : tasmop; + begin + if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then + fromsize := tosize; + case fromsize of + OS_S8: + Op:=A_LDSB;{Load Signed Byte} + OS_8: + Op:=A_LDUB;{Load Unsigned Byte} + OS_S16: + Op:=A_LDSH;{Load Signed Halfword} + OS_16: + Op:=A_LDUH;{Load Unsigned Halfword} + OS_S32, + OS_32: + Op:=A_LD;{Load Word} + OS_S64, + OS_64: + Op:=A_LDD;{Load a Long Word} + else + InternalError(2002122101); + end; + handle_load_store(list,false,op,reg,ref); + end; + + + procedure TCgSparc.a_load_reg_reg(list:TAasmOutput;fromsize,tosize:tcgsize;reg1,reg2:tregister); + var + instr : taicpu; + begin + if (tcgsize2size[tosize]<tcgsize2size[fromsize]) or + ( + (tcgsize2size[tosize] = tcgsize2size[fromsize]) and + (tosize <> fromsize) and + not(fromsize in [OS_32,OS_S32]) + ) then + begin + case tosize of + OS_8 : + a_op_const_reg_reg(list,OP_AND,tosize,$ff,reg1,reg2); + OS_16 : + a_op_const_reg_reg(list,OP_AND,tosize,$ffff,reg1,reg2); + OS_32, + OS_S32 : + begin + instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; + OS_S8 : + begin + list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,24,reg2)); + list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,24,reg2)); + end; + OS_S16 : + begin + list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,16,reg2)); + list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,16,reg2)); + end; + else + internalerror(2002090901); + end; + end + else + begin + if reg1<>reg2 then + begin + { same size, only a register mov required } + instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; + end; + end; + + + procedure TCgSparc.a_loadaddr_ref_reg(list : TAasmOutput;const ref : TReference;r : tregister); + var + tmpref,href : treference; + hreg,tmpreg : tregister; + begin + href:=ref; + if (href.base=NR_NO) and (href.index<>NR_NO) then + internalerror(200306171); + + if (cs_create_pic in aktmoduleswitches) and + assigned(href.symbol) then + begin + tmpreg:=GetIntRegister(list,OS_ADDR); + reference_reset(tmpref); + tmpref.symbol:=href.symbol; + tmpref.refaddr:=addr_pic; + if not(pi_needs_got in current_procinfo.flags) then + internalerror(200501161); + tmpref.base:=current_procinfo.got; + list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg)); + href.symbol:=nil; + if (href.index<>NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,href.index,tmpreg)); + href.index:=tmpreg; + end + else + begin + if href.base<>NR_NO then + href.index:=tmpreg + else + href.base:=tmpreg; + end; + end; + + { At least big offset (need SETHI), maybe base and maybe index } + if assigned(href.symbol) or + (href.offset<simm13lo) or + (href.offset>simm13hi) then + begin + hreg:=GetAddressRegister(list); + reference_reset(tmpref); + tmpref.symbol := href.symbol; + tmpref.offset := href.offset; + tmpref.refaddr := addr_hi; + list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg)); + { Only the low part is left } + tmpref.refaddr:=addr_lo; + list.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg)); + if href.base<>NR_NO then + begin + if href.index<>NR_NO then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.base,hreg)); + list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.index,r)); + end + else + list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.base,r)); + end + else + begin + if hreg<>r then + a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,r); + end; + end + else + { At least small offset, maybe base and maybe index } + if href.offset<>0 then + begin + if href.base<>NR_NO then + begin + if href.index<>NR_NO then + begin + hreg:=GetAddressRegister(list); + list.concat(taicpu.op_reg_const_reg(A_ADD,href.base,href.offset,hreg)); + list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,href.index,r)); + end + else + list.concat(taicpu.op_reg_const_reg(A_ADD,href.base,href.offset,r)); + end + else + list.concat(taicpu.op_const_reg(A_MOV,href.offset,r)); + end + else + { Both base and index } + if href.index<>NR_NO then + list.concat(taicpu.op_reg_reg_reg(A_ADD,href.base,href.index,r)) + else + { Only base } + if href.base<>NR_NO then + a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r) + else + { only offset, can be generated by absolute } + a_load_const_reg(list,OS_ADDR,href.offset,r); + end; + + + procedure TCgSparc.a_loadfpu_reg_reg(list:TAasmOutput;size:tcgsize;reg1, reg2:tregister); + const + FpuMovInstr : Array[OS_F32..OS_F64] of TAsmOp = + (A_FMOVS,A_FMOVD); + var + instr : taicpu; + begin + if reg1<>reg2 then + begin + instr:=taicpu.op_reg_reg(fpumovinstr[size],reg1,reg2); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; + end; + + + procedure TCgSparc.a_loadfpu_ref_reg(list:TAasmOutput;size:tcgsize;const ref:TReference;reg:tregister); + const + FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp = + (A_LDF,A_LDDF); + begin + handle_load_store(list,false,fpuloadinstr[size],reg,ref); + end; + + + procedure TCgSparc.a_loadfpu_reg_ref(list:TAasmOutput;size:tcgsize;reg:tregister;const ref:TReference); + const + FpuLoadInstr : Array[OS_F32..OS_F64] of TAsmOp = + (A_STF,A_STDF); + begin + handle_load_store(list,true,fpuloadinstr[size],reg,ref); + end; + + + procedure TCgSparc.a_op_const_reg(list:TAasmOutput;Op:TOpCG;size:tcgsize;a:aint;reg:TRegister); + begin + if Op in [OP_NEG,OP_NOT] then + internalerror(200306011); + if (a=0) then + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],reg,NR_G0,reg)) + else + handle_reg_const_reg(list,TOpCG2AsmOp[op],reg,a,reg); + end; + + + procedure TCgSparc.a_op_reg_reg(list:TAasmOutput;Op:TOpCG;size:TCGSize;src, dst:TRegister); + var + a : aint; + begin + Case Op of + OP_NEG : + list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],src,dst)); + OP_NOT : + begin + case size of + OS_8 : + a:=aint($ffffff00); + OS_16 : + a:=aint($ffff0000); + else + a:=0; + end; + handle_reg_const_reg(list,A_XNOR,src,a,dst); + end; + else + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src,dst)); + end; + end; + + + procedure TCgSparc.a_op_const_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;a:aint;src, dst:tregister); + var + power : longInt; + begin + case op of + OP_MUL, + OP_IMUL: + begin + if ispowerof2(a,power) then + begin + { can be done with a shift } + inherited a_op_const_reg_reg(list,op,size,a,src,dst); + exit; + end; + end; + OP_SUB, + OP_ADD : + begin + if (a=0) then + begin + a_load_reg_reg(list,size,size,src,dst); + exit; + end; + end; + end; + handle_reg_const_reg(list,TOpCG2AsmOp[op],src,a,dst); + end; + + + procedure TCgSparc.a_op_reg_reg_reg(list:TAasmOutput;op:TOpCg;size:tcgsize;src1, src2, dst:tregister); + begin + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst)); + end; + + + procedure tcgsparc.a_op_const_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); + var + power : longInt; + tmpreg1,tmpreg2 : tregister; + begin + ovloc.loc:=LOC_VOID; + case op of + OP_SUB, + OP_ADD : + begin + if (a=0) then + begin + a_load_reg_reg(list,size,size,src,dst); + exit; + end; + end; + end; + if setflags then + begin + handle_reg_const_reg(list,TOpCG2AsmOpWithFlags[op],src,a,dst); + case op of + OP_MUL: + begin + tmpreg1:=GetIntRegister(list,OS_INT); + list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1)); + list.concat(taicpu.op_reg_reg(A_CMP,NR_G0,tmpreg1)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + end; + OP_IMUL: + begin + tmpreg1:=GetIntRegister(list,OS_INT); + tmpreg2:=GetIntRegister(list,OS_INT); + list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1)); + list.concat(taicpu.op_reg_const_reg(A_SRL,dst,31,tmpreg2)); + list.concat(taicpu.op_reg_reg(A_CMP,tmpreg1,tmpreg2)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + end; + end; + end + else + handle_reg_const_reg(list,TOpCG2AsmOp[op],src,a,dst) + end; + + + procedure tcgsparc.a_op_reg_reg_reg_checkoverflow(list: taasmoutput; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); + var + tmpreg1,tmpreg2 : tregister; + begin + ovloc.loc:=LOC_VOID; + if setflags then + begin + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOpWithFlags[op],src2,src1,dst)); + case op of + OP_MUL: + begin + tmpreg1:=GetIntRegister(list,OS_INT); + list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1)); + list.concat(taicpu.op_reg_reg(A_CMP,NR_G0,tmpreg1)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + end; + OP_IMUL: + begin + tmpreg1:=GetIntRegister(list,OS_INT); + tmpreg2:=GetIntRegister(list,OS_INT); + list.concat(taicpu.op_reg_reg(A_MOV,NR_Y,tmpreg1)); + list.concat(taicpu.op_reg_const_reg(A_SRL,dst,31,tmpreg2)); + list.concat(taicpu.op_reg_reg(A_CMP,tmpreg1,tmpreg2)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + end; + end; + end + else + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],src2,src1,dst)) + end; + + + + {*************** compare instructructions ****************} + + procedure TCgSparc.a_cmp_const_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;a:aint;reg:tregister;l:tasmlabel); + begin + if (a=0) then + list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg,NR_G0,NR_G0)) + else + handle_reg_const_reg(list,A_SUBcc,reg,a,NR_G0); + a_jmp_cond(list,cmp_op,l); + end; + + + procedure TCgSparc.a_cmp_reg_reg_label(list:TAasmOutput;size:tcgsize;cmp_op:topcmp;reg1,reg2:tregister;l:tasmlabel); + begin + list.concat(taicpu.op_reg_reg_reg(A_SUBcc,reg2,reg1,NR_G0)); + a_jmp_cond(list,cmp_op,l); + end; + + + procedure TCgSparc.a_jmp_always(List:TAasmOutput;l:TAsmLabel); + begin + List.Concat(TAiCpu.op_sym(A_BA,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + end; + + + procedure tcgsparc.a_jmp_name(list : taasmoutput;const s : string); + begin + List.Concat(TAiCpu.op_sym(A_BA,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + end; + + + procedure TCgSparc.a_jmp_cond(list:TAasmOutput;cond:TOpCmp;l:TAsmLabel); + var + ai:TAiCpu; + begin + ai:=TAiCpu.Op_sym(A_Bxx,l); + ai.SetCondition(TOpCmp2AsmCond[cond]); + list.Concat(ai); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + end; + + + procedure TCgSparc.a_jmp_flags(list:TAasmOutput;const f:TResFlags;l:tasmlabel); + var + ai : taicpu; + op : tasmop; + begin + if f in [F_FE,F_FNE,F_FG,F_FL,F_FGE,F_FLE] then + op:=A_FBxx + else + op:=A_Bxx; + ai := Taicpu.op_sym(op,l); + ai.SetCondition(flags_to_cond(f)); + list.Concat(ai); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + end; + + + procedure TCgSparc.g_flags2reg(list:TAasmOutput;Size:TCgSize;const f:tresflags;reg:TRegister); + var + hl : tasmlabel; + begin + objectlibrary.getjumplabel(hl); + a_load_const_reg(list,size,1,reg); + a_jmp_flags(list,f,hl); + a_load_const_reg(list,size,0,reg); + a_label(list,hl); + end; + + + procedure tcgsparc.g_overflowCheck(List:TAasmOutput;const Loc:TLocation;def:TDef); + var + l : tlocation; + begin + l.loc:=LOC_VOID; + g_overflowCheck_loc(list,loc,def,l); + end; + + + procedure TCgSparc.g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation); + var + hl : tasmlabel; + ai:TAiCpu; + hflags : tresflags; + begin + if not(cs_check_overflow in aktlocalswitches) then + exit; + objectlibrary.getjumplabel(hl); + case ovloc.loc of + LOC_VOID: + begin + if not((def.deftype=pointerdef) or + ((def.deftype=orddef) and + (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then + begin + ai:=TAiCpu.Op_sym(A_Bxx,hl); + ai.SetCondition(C_NO); + list.Concat(ai); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + end + else + a_jmp_cond(list,OC_AE,hl); + end; + LOC_FLAGS: + begin + hflags:=ovloc.resflags; + inverse_flags(hflags); + cg.a_jmp_flags(list,hflags,hl); + end; + else + internalerror(200409281); + end; + + a_call_name(list,'FPC_OVERFLOW'); + a_label(list,hl); + end; + + { *********** entry/exit code and address loading ************ } + + procedure TCgSparc.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean); + begin + if nostackframe then + exit; + { Althogh the SPARC architecture require only word alignment, software + convention and the operating system require every stack frame to be double word + aligned } + LocalSize:=align(LocalSize,8); + { Execute the SAVE instruction to get a new register window and create a new + stack frame. In the "SAVE %i6,size,%i6" the first %i6 is related to the state + before execution of the SAVE instrucion so it is the caller %i6, when the %i6 + after execution of that instruction is the called function stack pointer} + { constant can be 13 bit signed, since it's negative, size can be max. 4096 } + if LocalSize>4096 then + begin + a_load_const_reg(list,OS_ADDR,-LocalSize,NR_G1); + list.concat(Taicpu.Op_reg_reg_reg(A_SAVE,NR_STACK_POINTER_REG,NR_G1,NR_STACK_POINTER_REG)); + end + else + list.concat(Taicpu.Op_reg_const_reg(A_SAVE,NR_STACK_POINTER_REG,-LocalSize,NR_STACK_POINTER_REG)); + if (cs_create_pic in aktmoduleswitches) and + (pi_needs_got in current_procinfo.flags) then + begin + current_procinfo.got:=NR_L7; + end; + end; + + + procedure TCgSparc.g_restore_standard_registers(list:taasmoutput); + begin + { The sparc port uses the sparc standard calling convetions so this function has no used } + end; + + + procedure TCgSparc.g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean); + var + hr : treference; + begin + if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then + begin + reference_reset(hr); + hr.offset:=12; + hr.refaddr:=addr_full; + if nostackframe then + begin + hr.base:=NR_O7; + list.concat(taicpu.op_ref_reg(A_JMPL,hr,NR_G0)); + list.concat(Taicpu.op_none(A_NOP)) + end + else + begin + { We use trivial restore in the delay slot of the JMPL instruction, as we + already set result onto %i0 } + hr.base:=NR_I7; + list.concat(taicpu.op_ref_reg(A_JMPL,hr,NR_G0)); + list.concat(Taicpu.op_none(A_RESTORE)); + end; + end + else + begin + if nostackframe then + begin + { Here we need to use RETL instead of RET so it uses %o7 } + list.concat(Taicpu.op_none(A_RETL)); + list.concat(Taicpu.op_none(A_NOP)) + end + else + begin + { We use trivial restore in the delay slot of the JMPL instruction, as we + already set result onto %i0 } + list.concat(Taicpu.op_none(A_RET)); + list.concat(Taicpu.op_none(A_RESTORE)); + end; + end; + end; + + + procedure TCgSparc.g_save_standard_registers(list : taasmoutput); + begin + { The sparc port uses the sparc standard calling convetions so this function has no used } + end; + + + { ************* concatcopy ************ } + + procedure tcgsparc.g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint); + var + paraloc1,paraloc2,paraloc3 : TCGPara; + begin + paraloc1.init; + paraloc2.init; + paraloc3.init; + paramanager.getintparaloc(pocall_default,1,paraloc1); + paramanager.getintparaloc(pocall_default,2,paraloc2); + paramanager.getintparaloc(pocall_default,3,paraloc3); + paramanager.allocparaloc(list,paraloc3); + a_param_const(list,OS_INT,len,paraloc3); + paramanager.allocparaloc(list,paraloc2); + a_paramaddr_ref(list,dest,paraloc2); + paramanager.allocparaloc(list,paraloc2); + a_paramaddr_ref(list,source,paraloc1); + paramanager.freeparaloc(list,paraloc3); + paramanager.freeparaloc(list,paraloc2); + paramanager.freeparaloc(list,paraloc1); + alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); + alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default)); + a_call_name(list,'FPC_MOVE'); + dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default)); + dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); + paraloc3.done; + paraloc2.done; + paraloc1.done; + end; + + + procedure TCgSparc.g_concatcopy(list:taasmoutput;const source,dest:treference;len:aint); + var + tmpreg1, + hreg, + countreg: TRegister; + src, dst: TReference; + lab: tasmlabel; + count, count2: aint; + begin + if len>high(longint) then + internalerror(2002072704); + { anybody wants to determine a good value here :)? } + if len>100 then + g_concatcopy_move(list,source,dest,len) + else + begin + reference_reset(src); + reference_reset(dst); + { load the address of source into src.base } + src.base:=GetAddressRegister(list); + a_loadaddr_ref_reg(list,source,src.base); + { load the address of dest into dst.base } + dst.base:=GetAddressRegister(list); + a_loadaddr_ref_reg(list,dest,dst.base); + { generate a loop } + count:=len div 4; + if count>4 then + begin + { the offsets are zero after the a_loadaddress_ref_reg and just } + { have to be set to 8. I put an Inc there so debugging may be } + { easier (should offset be different from zero here, it will be } + { easy to notice in the generated assembler } + countreg:=GetIntRegister(list,OS_INT); + tmpreg1:=GetIntRegister(list,OS_INT); + a_load_const_reg(list,OS_INT,count,countreg); + { explicitely allocate R_O0 since it can be used safely here } + { (for holding date that's being copied) } + objectlibrary.getjumplabel(lab); + a_label(list, lab); + list.concat(taicpu.op_ref_reg(A_LD,src,tmpreg1)); + list.concat(taicpu.op_reg_ref(A_ST,tmpreg1,dst)); + list.concat(taicpu.op_reg_const_reg(A_ADD,src.base,4,src.base)); + list.concat(taicpu.op_reg_const_reg(A_ADD,dst.base,4,dst.base)); + list.concat(taicpu.op_reg_const_reg(A_SUBcc,countreg,1,countreg)); + a_jmp_cond(list,OC_NE,lab); + list.concat(taicpu.op_none(A_NOP)); + { keep the registers alive } + list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg)); + list.concat(taicpu.op_reg_reg(A_MOV,src.base,src.base)); + list.concat(taicpu.op_reg_reg(A_MOV,dst.base,dst.base)); + len := len mod 4; + end; + { unrolled loop } + count:=len div 4; + if count>0 then + begin + tmpreg1:=GetIntRegister(list,OS_INT); + for count2 := 1 to count do + begin + list.concat(taicpu.op_ref_reg(A_LD,src,tmpreg1)); + list.concat(taicpu.op_reg_ref(A_ST,tmpreg1,dst)); + inc(src.offset,4); + inc(dst.offset,4); + end; + len := len mod 4; + end; + if (len and 4) <> 0 then + begin + hreg:=GetIntRegister(list,OS_INT); + a_load_ref_reg(list,OS_32,OS_32,src,hreg); + a_load_reg_ref(list,OS_32,OS_32,hreg,dst); + inc(src.offset,4); + inc(dst.offset,4); + end; + { copy the leftovers } + if (len and 2) <> 0 then + begin + hreg:=GetIntRegister(list,OS_INT); + a_load_ref_reg(list,OS_16,OS_16,src,hreg); + a_load_reg_ref(list,OS_16,OS_16,hreg,dst); + inc(src.offset,2); + inc(dst.offset,2); + end; + if (len and 1) <> 0 then + begin + hreg:=GetIntRegister(list,OS_INT); + a_load_ref_reg(list,OS_8,OS_8,src,hreg); + a_load_reg_ref(list,OS_8,OS_8,hreg,dst); + end; + end; + end; + + + procedure tcgsparc.g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint); + var + src, dst: TReference; + tmpreg1, + countreg: TRegister; + i : aint; + lab: tasmlabel; + begin + if len>31 then + g_concatcopy_move(list,source,dest,len) + else + begin + reference_reset(src); + reference_reset(dst); + { load the address of source into src.base } + src.base:=GetAddressRegister(list); + a_loadaddr_ref_reg(list,source,src.base); + { load the address of dest into dst.base } + dst.base:=GetAddressRegister(list); + a_loadaddr_ref_reg(list,dest,dst.base); + { generate a loop } + if len>4 then + begin + { the offsets are zero after the a_loadaddress_ref_reg and just } + { have to be set to 8. I put an Inc there so debugging may be } + { easier (should offset be different from zero here, it will be } + { easy to notice in the generated assembler } + countreg:=GetIntRegister(list,OS_INT); + tmpreg1:=GetIntRegister(list,OS_INT); + a_load_const_reg(list,OS_INT,len,countreg); + { explicitely allocate R_O0 since it can be used safely here } + { (for holding date that's being copied) } + objectlibrary.getjumplabel(lab); + a_label(list, lab); + list.concat(taicpu.op_ref_reg(A_LDUB,src,tmpreg1)); + list.concat(taicpu.op_reg_ref(A_STB,tmpreg1,dst)); + list.concat(taicpu.op_reg_const_reg(A_ADD,src.base,1,src.base)); + list.concat(taicpu.op_reg_const_reg(A_ADD,dst.base,1,dst.base)); + list.concat(taicpu.op_reg_const_reg(A_SUBcc,countreg,1,countreg)); + a_jmp_cond(list,OC_NE,lab); + list.concat(taicpu.op_none(A_NOP)); + { keep the registers alive } + list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg)); + list.concat(taicpu.op_reg_reg(A_MOV,src.base,src.base)); + list.concat(taicpu.op_reg_reg(A_MOV,dst.base,dst.base)); + end + else + begin + { unrolled loop } + tmpreg1:=GetIntRegister(list,OS_INT); + for i:=1 to len do + begin + list.concat(taicpu.op_ref_reg(A_LDUB,src,tmpreg1)); + list.concat(taicpu.op_reg_ref(A_STB,tmpreg1,dst)); + inc(src.offset); + inc(dst.offset); + end; + end; + end; + end; + + + procedure tcgsparc.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint); + var + make_global : boolean; + href : treference; + begin + if not(procdef.proctypeoption in [potype_function,potype_procedure]) then + Internalerror(200006137); + if not assigned(procdef._class) or + (procdef.procoptions*[po_classmethod, po_staticmethod, + po_methodpointer, po_interrupt, po_iocheck]<>[]) then + Internalerror(200006138); + if procdef.owner.symtabletype<>objectsymtable then + Internalerror(200109191); + + make_global:=false; + if (not current_module.is_unit) or + (procdef.owner.defowner.owner.symtabletype=globalsymtable) then + make_global:=true; + + if make_global then + List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0)) + else + List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0)); + + { set param1 interface to self } + g_adjust_self_value(list,procdef,ioffset); + + if po_virtualmethod in procdef.procoptions then + begin + if (procdef.extnumber=$ffff) then + Internalerror(200006139); + { mov 0(%rdi),%rax ; load vmt} + reference_reset_base(href,NR_O0,0); + cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_L0); + { jmp *vmtoffs(%eax) ; method offs } + reference_reset_base(href,NR_L0,procdef._class.vmtmethodoffset(procdef.extnumber)); + list.concat(taicpu.op_ref_reg(A_LD,href,NR_L1)); + list.concat(taicpu.op_reg(A_JMP,NR_L1)); + end + else + list.concat(taicpu.op_sym(A_BA,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + + List.concat(Tai_symbol_end.Createname(labelname)); + end; + +{**************************************************************************** + TCG64Sparc +****************************************************************************} + + + procedure tcg64sparc.a_load64_reg_ref(list : taasmoutput;reg : tregister64;const ref : treference); + var + tmpref: treference; + begin + { Override this function to prevent loading the reference twice } + tmpref:=ref; + cg.a_load_reg_ref(list,OS_32,OS_32,reg.reghi,tmpref); + inc(tmpref.offset,4); + cg.a_load_reg_ref(list,OS_32,OS_32,reg.reglo,tmpref); + end; + + + procedure tcg64sparc.a_load64_ref_reg(list : taasmoutput;const ref : treference;reg : tregister64); + var + tmpref: treference; + begin + { Override this function to prevent loading the reference twice } + tmpref:=ref; + cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reghi); + inc(tmpref.offset,4); + cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reglo); + end; + + + procedure tcg64sparc.a_param64_ref(list : taasmoutput;const r : treference;const paraloc : tcgpara); + var + hreg64 : tregister64; + begin + { Override this function to prevent loading the reference twice. + Use here some extra registers, but those are optimized away by the RA } + hreg64.reglo:=cg.GetIntRegister(list,OS_32); + hreg64.reghi:=cg.GetIntRegister(list,OS_32); + a_load64_ref_reg(list,r,hreg64); + a_param64_reg(list,hreg64,paraloc); + end; + + + procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean); + begin + case op of + OP_ADD : + begin + op1:=A_ADDCC; + if checkoverflow then + op2:=A_ADDXCC + else + op2:=A_ADDX; + end; + OP_SUB : + begin + op1:=A_SUBCC; + if checkoverflow then + op2:=A_SUBXCC + else + op2:=A_SUBX; + end; + OP_XOR : + begin + op1:=A_XOR; + op2:=A_XOR; + end; + OP_OR : + begin + op1:=A_OR; + op2:=A_OR; + end; + OP_AND : + begin + op1:=A_AND; + op2:=A_AND; + end; + else + internalerror(200203241); + end; + end; + + + procedure TCg64Sparc.a_op64_reg_reg(list:TAasmOutput;op:TOpCG;size : tcgsize;regsrc,regdst:TRegister64); + var + op1,op2 : TAsmOp; + begin + case op of + OP_NEG : + begin + { Use the simple code: y=0-z } + list.concat(taicpu.op_reg_reg_reg(A_SUBcc,NR_G0,regsrc.reglo,regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SUBX,NR_G0,regsrc.reghi,regdst.reghi)); + exit; + end; + OP_NOT : + begin + list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reglo,NR_G0,regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reghi,NR_G0,regdst.reghi)); + exit; + end; + end; + get_64bit_ops(op,op1,op2,false); + list.concat(taicpu.op_reg_reg_reg(op1,regdst.reglo,regsrc.reglo,regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(op2,regdst.reghi,regsrc.reghi,regdst.reghi)); + end; + + + procedure TCg64Sparc.a_op64_const_reg(list:TAasmOutput;op:TOpCG;size : tcgsize;value:int64;regdst:TRegister64); + var + op1,op2:TAsmOp; + begin + case op of + OP_NEG, + OP_NOT : + internalerror(200306017); + end; + get_64bit_ops(op,op1,op2,false); + tcgsparc(cg).handle_reg_const_reg(list,op1,regdst.reglo,aint(lo(value)),regdst.reglo); + tcgsparc(cg).handle_reg_const_reg(list,op2,regdst.reghi,aint(hi(value)),regdst.reghi); + end; + + + procedure tcg64sparc.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64; regsrc,regdst : tregister64); + var + l : tlocation; + begin + a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,l); + end; + + + procedure tcg64sparc.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64); + var + l : tlocation; + begin + a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,l); + end; + + + procedure tcg64sparc.a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation); + var + op1,op2:TAsmOp; + begin + case op of + OP_NEG, + OP_NOT : + internalerror(200306017); + end; + get_64bit_ops(op,op1,op2,setflags); + tcgsparc(cg).handle_reg_const_reg(list,op1,regsrc.reglo,aint(lo(value)),regdst.reglo); + tcgsparc(cg).handle_reg_const_reg(list,op2,regsrc.reghi,aint(hi(value)),regdst.reghi); + end; + + + procedure tcg64sparc.a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation); + var + op1,op2:TAsmOp; + begin + case op of + OP_NEG, + OP_NOT : + internalerror(200306017); + end; + get_64bit_ops(op,op1,op2,setflags); + list.concat(taicpu.op_reg_reg_reg(op1,regsrc2.reglo,regsrc1.reglo,regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(op2,regsrc2.reghi,regsrc1.reghi,regdst.reghi)); + end; + + +begin + cg:=TCgSparc.Create; + cg64:=TCg64Sparc.Create; +end. diff --git a/compiler/sparc/cpubase.pas b/compiler/sparc/cpubase.pas new file mode 100644 index 0000000000..97a6a569a6 --- /dev/null +++ b/compiler/sparc/cpubase.pas @@ -0,0 +1,462 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Contains the base types for the SPARC + + 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 cpubase; + +{$i fpcdefs.inc} + +interface + +uses + globtype,strings,cutils,cclasses,aasmbase,cpuinfo,cgbase; + + +{***************************************************************************** + Assembler Opcodes +*****************************************************************************} + + type +{$WARNING CPU32 opcodes do not fully include the Ultra SPRAC instruction set.} + { don't change the order of these opcodes! } + TAsmOp=({$i opcode.inc}); + + {# This should define the array of instructions as string } + op2strtable=array[tasmop] of string[11]; + + Const + {# First value of opcode enumeration } + firstop = low(tasmop); + {# Last value of opcode enumeration } + lastop = high(tasmop); + + std_op2str:op2strtable=({$i strinst.inc}); + +{***************************************************************************** + Registers +*****************************************************************************} + + type + { Number of registers used for indexing in tables } + tregisterindex=0..{$i rspnor.inc}-1; + totherregisterset = set of tregisterindex; + + const + { Available Superregisters } + {$i rspsup.inc} + + { No Subregisters } + R_SUBWHOLE = R_SUBD; + + { Available Registers } + {$i rspcon.inc} + + first_int_imreg = $20; + first_fpu_imreg = $20; + + { MM Super register first and last } + first_mm_supreg = 0; + first_mm_imreg = 0; + +{$warning TODO Calculate bsstart} + regnumber_count_bsstart = 128; + + regnumber_table : array[tregisterindex] of tregister = ( + {$i rspnum.inc} + ); + + regstabs_table : array[tregisterindex] of ShortInt = ( + {$i rspstab.inc} + ); + + regdwarf_table : array[tregisterindex] of ShortInt = ( + {$i rspdwrf.inc} + ); + + +{***************************************************************************** + Conditions +*****************************************************************************} + + type + TAsmCond=(C_None, + C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE, + C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP, + C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z, + C_FE,C_FG,C_FL,C_FGE,C_FLE,C_FNE + ); + + const + cond2str:array[TAsmCond] of string[3]=('', + 'gu','cc','cs','leu','cs','e','g','ge','l','le','leu','cs', + 'cc','gu','cc','ne','le','l','ge','g','vc','XX', + 'pos','ne','vs','XX','XX','XX','vs','e', + 'e','g','l','ge','le','ne' + ); + + const + CondAsmOps=2; + CondAsmOp:array[0..CondAsmOps-1] of TAsmOp=( + A_Bxx,A_FBxx + ); + CondAsmOpStr:array[0..CondAsmOps-1] of string[7]=( + 'B','FB' + ); + + +{***************************************************************************** + Flags +*****************************************************************************} + + type + TResFlags=( + { Integer results } + F_E, {Equal} + F_NE, {Not Equal} + F_G, {Greater} + F_L, {Less} + F_GE, {Greater or Equal} + F_LE, {Less or Equal} + F_A, {Above} + F_AE, {Above or Equal} + F_B, {Below} + F_BE, {Below or Equal} + F_C, {Carry} + F_NC, {Not Carry} + { Floating point results } + F_FE, {Equal} + F_FNE, {Not Equal} + F_FG, {Greater} + F_FL, {Less} + F_FGE, {Greater or Equal} + F_FLE {Less or Equal} + ); + +{***************************************************************************** + Operand Sizes +*****************************************************************************} + + +{***************************************************************************** + Constants +*****************************************************************************} + + const + max_operands = 3; + + {# Constant defining possibly all registers which might require saving } + ALL_OTHERREGISTERS = []; + + general_superregisters = [RS_O0..RS_I7]; + + {# Table of registers which can be allocated by the code generator + internally, when generating the code. + } + { legend: } + { xxxregs = set of all possibly used registers of that type in the code } + { generator } + { usableregsxxx = set of all 32bit components of registers that can be } + { possible allocated to a regvar or using getregisterxxx (this } + { excludes registers which can be only used for parameter } + { passing on ABI's that define this) } + { c_countusableregsxxx = amount of registers in the usableregsxxx set } + + maxintregs = 8; + { to determine how many registers to use for regvars } + maxintscratchregs = 3; + usableregsint = [RS_L0..RS_L7]; + c_countusableregsint = 8; + + maxfpuregs = 8; + usableregsfpu=[RS_F0..RS_F31]; + c_countusableregsfpu=32; + + mmregs = []; + usableregsmm = []; + c_countusableregsmm = 0; + + { no distinction on this platform } + maxaddrregs = 0; + addrregs = []; + usableregsaddr = []; + c_countusableregsaddr = 0; + +{$warning firstsaveintreg shall be RS_NO} + firstsaveintreg = RS_L0; { Temporary, having RS_NO is broken } + lastsaveintreg = RS_L0; { L0..L7 are already saved, I0..O7 are parameter } + firstsavefpureg = RS_F2; { F0..F1 is used for return value } + lastsavefpureg = RS_F31; + firstsavemmreg = RS_INVALID; + lastsavemmreg = RS_INVALID; + + maxvarregs = 8; + varregs : Array [1..maxvarregs] of Tsuperregister = + (RS_L0,RS_L1,RS_L2,RS_L3,RS_L4,RS_L5,RS_L6,RS_L7); + + maxfpuvarregs = 1; + fpuvarregs : Array [1..maxfpuvarregs] of TsuperRegister = + (RS_F2); + + { + max_param_regs_int = 6; + param_regs_int: Array[1..max_param_regs_int] of TCpuRegister = + (R_3,R_4,R_5,R_6,R_7,R_8,R_9,R_10); + + max_param_regs_fpu = 13; + param_regs_fpu: Array[1..max_param_regs_fpu] of TCpuRegister = + (R_F1,R_F2,R_F3,R_F4,R_F5,R_F6,R_F7,R_F8,R_F9,R_F10,R_F11,R_F12,R_F13); + + max_param_regs_mm = 13; + param_regs_mm: Array[1..max_param_regs_mm] of TCpuRegister = + (R_M1,R_M2,R_M3,R_M4,R_M5,R_M6,R_M7,R_M8,R_M9,R_M10,R_M11,R_M12,R_M13); + } + + +{***************************************************************************** + Default generic sizes +*****************************************************************************} + + {# Defines the default address size for a processor, } + OS_ADDR = OS_32; + {# the natural int size for a processor, } + OS_INT = OS_32; + OS_SINT = OS_S32; + {# the maximum float size for a processor, } + OS_FLOAT = OS_F64; + {# the size of a vector register for a processor } + OS_VECTOR = OS_M64; + +{***************************************************************************** + Generic Register names +*****************************************************************************} + + {# Stack pointer register } + NR_STACK_POINTER_REG = NR_O6; + RS_STACK_POINTER_REG = RS_O6; + {# Frame pointer register } + NR_FRAME_POINTER_REG = NR_I6; + RS_FRAME_POINTER_REG = RS_I6; + {# Register for addressing absolute data in a position independant way, + such as in PIC code. The exact meaning is ABI specific. For + further information look at GCC source : PIC_OFFSET_TABLE_REGNUM + + Taken from GCC rs6000.h + } +{$warning As indicated in rs6000.h, but can't find it anywhere else!} + {PIC_OFFSET_REG = R_30;} + { Return address for DWARF } + NR_RETURN_ADDRESS_REG = NR_I7; + { the return_result_reg, is used inside the called function to store its return + value when that is a scalar value otherwise a pointer to the address of the + result is placed inside it } + { Results are returned in this register (32-bit values) } + NR_FUNCTION_RETURN_REG = NR_I0; + RS_FUNCTION_RETURN_REG = RS_I0; + { Low part of 64bit return value } + NR_FUNCTION_RETURN64_LOW_REG = NR_I1; + RS_FUNCTION_RETURN64_LOW_REG = RS_I1; + { High part of 64bit return value } + NR_FUNCTION_RETURN64_HIGH_REG = NR_I0; + RS_FUNCTION_RETURN64_HIGH_REG = RS_I0; + { The value returned from a function is available in this register } + NR_FUNCTION_RESULT_REG = NR_O0; + RS_FUNCTION_RESULT_REG = RS_O0; + { The lowh part of 64bit value returned from a function } + NR_FUNCTION_RESULT64_LOW_REG = NR_O1; + RS_FUNCTION_RESULT64_LOW_REG = RS_O1; + { The high part of 64bit value returned from a function } + NR_FUNCTION_RESULT64_HIGH_REG = NR_O0; + RS_FUNCTION_RESULT64_HIGH_REG = RS_O0; + + NR_FPU_RESULT_REG = NR_F0; + NR_MM_RESULT_REG = NR_NO; + + PARENT_FRAMEPOINTER_OFFSET = 68; { o0 } + + +{***************************************************************************** + GCC /ABI linking information +*****************************************************************************} + + {# Registers which must be saved when calling a routine declared as + cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers + saved should be the ones as defined in the target ABI and / or GCC. + + This value can be deduced from CALLED_USED_REGISTERS array in the + GCC source. + } + saved_standard_registers : array[0..0] of tsuperregister = (RS_NO); + + {# Required parameter alignment when calling a routine declared as + stdcall and cdecl. The alignment value should be the one defined + by GCC or the target ABI. + + The value of this constant is equal to the constant + PARM_BOUNDARY / BITS_PER_UNIT in the GCC source. + } + std_param_align = 4; { for 32-bit version only } + + +{***************************************************************************** + CPU Dependent Constants +*****************************************************************************} + + const + simm13lo=-4096; + simm13hi=4095; + +{***************************************************************************** + Helpers +*****************************************************************************} + + function is_calljmp(o:tasmop):boolean; + + procedure inverse_flags(var f: TResFlags); + function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} + function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} + + function flags_to_cond(const f: TResFlags) : TAsmCond; + function cgsize2subreg(s:Tcgsize):Tsubregister; + function reg_cgsize(const reg: tregister): tcgsize; + function std_regname(r:Tregister):string; + function std_regnum_search(const s:string):Tregister; + function findreg_by_number(r:Tregister):tregisterindex; + + +implementation + + uses + rgBase,verbose; + + const + std_regname_table : TRegNameTAble = ( + {$i rspstd.inc} + ); + + regnumber_index : TRegisterIndexTable = ( + {$i rsprni.inc} + ); + + std_regname_index : TRegisterIndexTable = ( + {$i rspsri.inc} + ); + + +{***************************************************************************** + Helpers +*****************************************************************************} + + function is_calljmp(o:tasmop):boolean; + const + CallJmpOp=[A_JMPL..A_CBccc]; + begin + is_calljmp:=(o in CallJmpOp); + end; + + + procedure inverse_flags(var f: TResFlags); + const + inv_flags: array[TResFlags] of TResFlags = + (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_BE,F_B,F_AE,F_A,F_NC,F_C, + F_FNE,F_FE,F_FLE,F_FGE,F_FL,F_FG); + begin + f:=inv_flags[f]; + end; + + + function flags_to_cond(const f:TResFlags):TAsmCond; + const + flags_2_cond:array[TResFlags] of TAsmCond= + (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_A,C_AE,C_B,C_BE,C_C,C_NC, + C_FE,C_FNE,C_FG,C_FL,C_FGE,C_FLE); + begin + result:=flags_2_cond[f]; + end; + + + function cgsize2subreg(s:Tcgsize):Tsubregister; + begin + if s in [OS_64,OS_S64] then + cgsize2subreg:=R_SUBQ + else + cgsize2subreg:=R_SUBWHOLE; + end; + + + function reg_cgsize(const reg: tregister): tcgsize; + begin + case getregtype(reg) of + R_INTREGISTER : + result:=OS_32; + R_FPUREGISTER : + begin + if getsubreg(reg)=R_SUBFD then + result:=OS_F64 + else + result:=OS_F32; + end; + else + internalerror(200303181); + end; + end; + + + function findreg_by_number(r:Tregister):tregisterindex; + begin + result:=findreg_by_number_table(r,regnumber_index); + end; + + + function std_regname(r:Tregister):string; + var + p : tregisterindex; + begin + p:=findreg_by_number(r); + if p<>0 then + result:=std_regname_table[p] + else + result:=generic_regname(r); + end; + + + function std_regnum_search(const s:string):Tregister; + begin + result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)]; + end; + + + function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} + const + inverse: array[TAsmCond] of TAsmCond=(C_None, + C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE, + C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P, + C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ, + C_FNE,C_FLE,C_FGE,C_FL,C_FG,C_FE + ); + begin + result := inverse[c]; + end; + + function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE} + begin + result := c1 = c2; + end; + +end. diff --git a/compiler/sparc/cpugas.pas b/compiler/sparc/cpugas.pas new file mode 100644 index 0000000000..9c85857f46 --- /dev/null +++ b/compiler/sparc/cpugas.pas @@ -0,0 +1,205 @@ +{ + Copyright (c) 1999-2003 by Florian Klaempfl + + This unit implements an asmoutput class for SPARC AT&T syntax + + 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 cpugas; + +{$i fpcdefs.inc} + +interface + + uses + cpubase, + aasmtai,aasmcpu,assemble,aggas; + + type + TGasSPARC=class(TGnuAssembler) + procedure WriteInstruction(hp:Tai);override; + end; + +implementation + + uses + cutils,systems, + verbose,itcpugas,cgbase,cgutils; + + + function GetReferenceString(var ref:TReference):string; + begin + GetReferenceString:=''; + with ref do + begin + if (base=NR_NO) and (index=NR_NO) then + begin + if assigned(symbol) then + GetReferenceString:=symbol.name; + if offset>0 then + GetReferenceString:=GetReferenceString+'+'+ToStr(offset) + else if offset<0 then + GetReferenceString:=GetReferenceString+ToStr(offset); + case refaddr of + addr_hi: + GetReferenceString:='%hi('+GetReferenceString+')'; + addr_lo: + GetReferenceString:='%lo('+GetReferenceString+')'; + end; + end + else + begin +{$ifdef extdebug} + if assigned(symbol) and + not(refaddr in [addr_pic,addr_lo]) then + internalerror(2003052601); +{$endif extdebug} + if base<>NR_NO then + GetReferenceString:=GetReferenceString+gas_regname(base); + if index=NR_NO then + begin + { if (Offset<simm13lo) or (Offset>simm13hi) then + internalerror(2003053008); } + if offset>0 then + GetReferenceString:=GetReferenceString+'+'+ToStr(offset) + else if offset<0 then + GetReferenceString:=GetReferenceString+ToStr(offset); + { + else if (offset=0) and not(assigned(symbol)) then + GetReferenceString:=GetReferenceString+ToStr(offset); + } + if assigned(symbol) then + begin + if refaddr=addr_lo then + GetReferenceString:='%lo('+symbol.name+')+'+GetReferenceString + else + GetReferenceString:=symbol.name+'+'+GetReferenceString; + end; + end + else + begin +{$ifdef extdebug} + if (Offset<>0) or assigned(symbol) then + internalerror(2003052603); +{$endif extdebug} + GetReferenceString:=GetReferenceString+'+'+gas_regname(index); + end; + end; + end; + end; + + + function getopstr(const Oper:TOper):string; + begin + with Oper do + case typ of + top_reg: + getopstr:=gas_regname(reg); + top_const: + getopstr:=tostr(longint(val)); + top_ref: + if (oper.ref^.refaddr in [addr_no,addr_pic]) or ((oper.ref^.refaddr=addr_lo) and ((oper.ref^.base<>NR_NO) or + (oper.ref^.index<>NR_NO))) then + getopstr:='['+getreferencestring(ref^)+']' + else + getopstr:=getreferencestring(ref^); + else + internalerror(10001); + end; + end; + + + procedure TGasSPARC.WriteInstruction(hp:Tai); + var + Op:TAsmOp; + s:String; + i:Integer; + begin + if hp.typ<>ait_instruction then + exit; + op:=taicpu(hp).opcode; + { translate pseudoops, this should be move to a separate pass later, so it's done before + peephole optimization } + case op of + A_FABSd: + begin + if (taicpu(hp).ops<>2) or + (taicpu(hp).oper[0]^.typ<>top_reg) or + (taicpu(hp).oper[1]^.typ<>top_reg) then + internalerror(200401045); + { FABSs %f<even>,%f<even> } + s:=#9+std_op2str[A_FABSs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^); + AsmWriteLn(s); + { FMOVs %f<odd>,%f<odd> } + inc(taicpu(hp).oper[0]^.reg); + inc(taicpu(hp).oper[1]^.reg); + s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^); + dec(taicpu(hp).oper[0]^.reg); + dec(taicpu(hp).oper[1]^.reg); + AsmWriteLn(s); + end; + A_FMOVd: + begin + if (taicpu(hp).ops<>2) or + (taicpu(hp).oper[0]^.typ<>top_reg) or + (taicpu(hp).oper[1]^.typ<>top_reg) then + internalerror(200401045); + { FMOVs %f<even>,%f<even> } + s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^); + AsmWriteLn(s); + { FMOVs %f<odd>,%f<odd> } + inc(taicpu(hp).oper[0]^.reg); + inc(taicpu(hp).oper[1]^.reg); + s:=#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^); + dec(taicpu(hp).oper[0]^.reg); + dec(taicpu(hp).oper[1]^.reg); + AsmWriteLn(s); + end + else + begin + { call maybe not translated to call } + s:=#9+std_op2str[op]+cond2str[taicpu(hp).condition]; + if taicpu(hp).delayslot_annulled then + s:=s+',a'; + if taicpu(hp).ops>0 then + begin + s:=s+#9+getopstr(taicpu(hp).oper[0]^); + for i:=1 to taicpu(hp).ops-1 do + s:=s+','+getopstr(taicpu(hp).oper[i]^); + end; + AsmWriteLn(s); + end; + end; + end; + + + const + as_sparc_as_info : tasminfo = + ( + id : as_gas; + idtxt : 'AS'; + asmbin : 'as'; + asmcmd : '-o $OBJ $ASM'; + supported_target : system_any; + flags : [af_allowdirect,af_needar,af_smartlink_sections]; + labelprefix : '.L'; + comment : '# '; + ); + +begin + RegisterAssembler(as_SPARC_as_info,TGasSPARC); +end. diff --git a/compiler/sparc/cpuinfo.pas b/compiler/sparc/cpuinfo.pas new file mode 100644 index 0000000000..e6658dcf1b --- /dev/null +++ b/compiler/sparc/cpuinfo.pas @@ -0,0 +1,68 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Basic Processor information for the SPARC + + 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 cpuinfo; + +{$i fpcdefs.inc} + +interface + +uses + globtype; + +type + bestreal = double; + ts32real = single; + ts64real = double; + ts80real = extended; + ts128real = type extended; + ts64comp = type extended; + pbestreal=^bestreal; + + { possible supported processors for this target } + tprocessors=(no_processor,SPARC_V7,SPARC_V8,SPARC_V9); + + tfputype =(no_fpu,fpu_soft,fpu_hard); + + +const + { calling conventions supported by the code generator } + supported_calling_conventions : tproccalloptions = [ + pocall_internproc, + pocall_stdcall, + pocall_cdecl, + pocall_cppdecl + ]; + + processorsstr : array[tprocessors] of string[10] = ('', + 'SPARC V7', + 'SPARC V8', + 'SPARC V9' + ); + + fputypestr : array[tfputype] of string[6] = ('', + 'SOFT', + 'HARD' + ); + +implementation + +end. diff --git a/compiler/sparc/cpunode.pas b/compiler/sparc/cpunode.pas new file mode 100644 index 0000000000..63fdb77d6f --- /dev/null +++ b/compiler/sparc/cpunode.pas @@ -0,0 +1,38 @@ +{****************************************************************************** + Copyright (c) 2000 by Florian Klaempfl + + Includes the iSPARC code generator + + 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 CpuNode; + +{$I fpcdefs.inc} + +interface +{ This unit is used to define the specific CPU implementations. All needed +actions are included in the INITALIZATION part of these units. This explains +the behaviour of such a unit having just a USES clause! } + +implementation + + uses + ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset, + ncpuadd,ncpucall,ncpumat,ncpuinln,ncpucnv,ncpuset, + { this not really a node } + rgcpu; + +end. diff --git a/compiler/sparc/cpupara.pas b/compiler/sparc/cpupara.pas new file mode 100644 index 0000000000..e8b9e3bdb4 --- /dev/null +++ b/compiler/sparc/cpupara.pas @@ -0,0 +1,325 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Calling conventions for the SPARC + + 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 cpupara; + +{$i fpcdefs.inc} + +interface + + uses + globtype, + cclasses, + aasmtai, + cpubase,cpuinfo, + symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase; + + type + TSparcParaManager=class(TParaManager) + function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; + function get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;override; + function get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;override; + {Returns a structure giving the information on the storage of the parameter + (which must be an integer parameter) + @param(nr Parameter number of routine, starting from 1)} + procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara : TCGPara);override; + function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override; + function create_varargs_paraloc_info(p : TAbstractProcDef; varargspara:tvarargsparalist):longint;override; + private + procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee); + procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; + var intparareg,parasize:longint); + end; + +implementation + + uses + cutils,verbose,systems, + defutil, + cgutils,cgobj; + + type + tparasupregs = array[0..5] of tsuperregister; + pparasupregs = ^tparasupregs; + const + paraoutsupregs : tparasupregs = (RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5); + parainsupregs : tparasupregs = (RS_I0,RS_I1,RS_I2,RS_I3,RS_I4,RS_I5); + + + function TSparcParaManager.get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet; + begin + result:=[RS_G1,RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5,RS_O6,RS_O7]; + end; + + + function tsparcparamanager.get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet; + begin + result:=[RS_F0..RS_F31]; + end; + + + procedure TSparcParaManager.GetIntParaLoc(calloption : tproccalloption; nr : longint;var cgpara : tcgpara); + var + paraloc : pcgparalocation; + begin + if nr<1 then + InternalError(2002100806); + cgpara.reset; + cgpara.size:=OS_INT; + cgpara.intsize:=tcgsize2size[OS_INT]; + cgpara.alignment:=std_param_align; + paraloc:=cgpara.add_location; + with paraloc^ do + begin + { The six first parameters are passed into registers } + dec(nr); + if nr<6 then + begin + loc:=LOC_REGISTER; + register:=newreg(R_INTREGISTER,(RS_O0+nr),R_SUBWHOLE); + end + else + begin + { The other parameters are passed on the stack } + loc:=LOC_REFERENCE; + reference.index:=NR_STACK_POINTER_REG; + reference.offset:=92+(nr-6)*4; + end; + size:=OS_INT; + end; + end; + + + { true if a parameter is too large to copy and only the address is pushed } + function tsparcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean; + begin + result:=false; + { var,out always require address } + if varspez in [vs_var,vs_out] then + begin + result:=true; + exit; + end; + case def.deftype of + arraydef: + result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or + is_open_array(def) or + is_array_of_const(def) or + is_array_constructor(def); + recorddef, + variantdef, + formaldef : + result:=true; + objectdef : + result:=is_object(def); + stringdef : + result:=(tstringdef(def).string_typ in [st_shortstring,st_longstring]); + procvardef : + result:=(po_methodpointer in tprocvardef(def).procoptions); + setdef : + result:=(tsetdef(def).settype<>smallset); + end; + end; + + + procedure tsparcparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee); + var + retcgsize : tcgsize; + begin + { Constructors return self instead of a boolean } + if (p.proctypeoption=potype_constructor) then + retcgsize:=OS_ADDR + else + retcgsize:=def_cgsize(p.rettype.def); + + location_reset(p.funcretloc[side],LOC_INVALID,OS_NO); + p.funcretloc[side].size:=retcgsize; + { void has no location } + if is_void(p.rettype.def) then + begin + p.funcretloc[side].loc:=LOC_VOID; + exit; + end; + + { Return in FPU register? } + if p.rettype.def.deftype=floatdef then + begin + p.funcretloc[side].loc:=LOC_FPUREGISTER; + p.funcretloc[side].register:=NR_FPU_RESULT_REG; + if retcgsize=OS_F64 then + setsubreg(p.funcretloc[side].register,R_SUBFD); + p.funcretloc[side].size:=retcgsize; + end + else + { Return in register? } + if not ret_in_param(p.rettype.def,p.proccalloption) then + begin +{$ifndef cpu64bit} + if retcgsize in [OS_64,OS_S64] then + begin + p.funcretloc[side].loc:=LOC_REGISTER; + { high } + if (side=callerside) or (po_inline in p.procoptions) then + p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG + else + p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG; + { low } + if (side=callerside) or (po_inline in p.procoptions) then + p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG + else + p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG; + end + else +{$endif cpu64bit} + begin + p.funcretloc[side].loc:=LOC_REGISTER; + p.funcretloc[side].size:=retcgsize; + if (side=callerside) or (po_inline in p.procoptions)then + p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize)) + else + p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize)); + end; + end + else + begin + p.funcretloc[side].loc:=LOC_REFERENCE; + p.funcretloc[side].size:=retcgsize; + end; + end; + + + procedure tsparcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist; + var intparareg,parasize:longint); + var + paraloc : pcgparalocation; + i : integer; + hp : tparavarsym; + paracgsize : tcgsize; + hparasupregs : pparasupregs; + paralen : longint; + begin + if side=callerside then + hparasupregs:=@paraoutsupregs + else + hparasupregs:=@parainsupregs; + for i:=0 to paras.count-1 do + begin + hp:=tparavarsym(paras[i]); + { currently only support C-style array of const, + there should be no location assigned to the vararg array itself } + if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and + is_array_of_const(hp.vartype.def) then + begin + paraloc:=hp.paraloc[side].add_location; + { hack: the paraloc must be valid, but is not actually used } + paraloc^.loc:=LOC_REGISTER; + paraloc^.register:=NR_G0; + paraloc^.size:=OS_ADDR; + break; + end; + + if push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption) then + paracgsize:=OS_ADDR + else + begin + paracgsize:=def_cgSize(hp.vartype.def); + if paracgsize=OS_NO then + paracgsize:=OS_ADDR; + end; + hp.paraloc[side].reset; + hp.paraloc[side].size:=paracgsize; + hp.paraloc[side].Alignment:=std_param_align; + paralen:=tcgsize2size[paracgsize]; + hp.paraloc[side].intsize:=paralen; + while paralen>0 do + begin + paraloc:=hp.paraloc[side].add_location; + { Floats are passed in int registers, + We can allocate at maximum 32 bits per register } + if paracgsize in [OS_64,OS_S64,OS_F32,OS_F64] then + paraloc^.size:=OS_32 + else + paraloc^.size:=paracgsize; + { ret in param? } + if vo_is_funcret in hp.varoptions then + begin + paraloc^.loc:=LOC_REFERENCE; + if side=callerside then + paraloc^.reference.index:=NR_STACK_POINTER_REG + else + paraloc^.reference.index:=NR_FRAME_POINTER_REG; + paraloc^.reference.offset:=64; + end + else if (intparareg<=high(tparasupregs)) then + begin + paraloc^.loc:=LOC_REGISTER; + paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[intparareg],R_SUBWHOLE); + inc(intparareg); + end + else + begin + paraloc^.loc:=LOC_REFERENCE; + if side=callerside then + paraloc^.reference.index:=NR_STACK_POINTER_REG + else + paraloc^.reference.index:=NR_FRAME_POINTER_REG; + paraloc^.reference.offset:=target_info.first_parm_offset+parasize; + { Parameters are aligned at 4 bytes } + inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(aint))); + end; + dec(paralen,tcgsize2size[paraloc^.size]); + end; + end; + end; + + + function TSparcParaManager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint; + var + intparareg, + parasize : longint; + begin + intparareg:=0; + parasize:=0; + { calculate the registers for the normal parameters } + create_paraloc_info_intern(p,callerside,p.paras,intparareg,parasize); + { append the varargs } + create_paraloc_info_intern(p,callerside,varargspara,intparareg,parasize); + result:=parasize; + end; + + + + function tsparcparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint; + var + intparareg, + parasize : longint; + begin + intparareg:=0; + parasize:=0; + create_paraloc_info_intern(p,side,p.paras,intparareg,parasize); + { Create Function result paraloc } + create_funcretloc_info(p,side); + { We need to return the size allocated on the stack } + result:=parasize; + end; + + +begin + ParaManager:=TSparcParaManager.create; +end. diff --git a/compiler/sparc/cpupi.pas b/compiler/sparc/cpupi.pas new file mode 100644 index 0000000000..e3e32bebed --- /dev/null +++ b/compiler/sparc/cpupi.pas @@ -0,0 +1,84 @@ +{ + Copyright (c) 2002 by Florian Klaempfl + + This unit contains the CPU specific part of tprocinfo + + 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 cpupi; + +{$i fpcdefs.inc} + +interface + + uses + cutils, + procinfo,cpuinfo, + psub; + + type + TSparcProcInfo=class(tcgprocinfo) + public + constructor create(aparent:tprocinfo);override; + procedure allocate_push_parasize(size:longint);override; + function calc_stackframe_size:longint;override; + end; + +implementation + + uses + systems,globals, + tgobj,paramgr,symconst; + + constructor tsparcprocinfo.create(aparent:tprocinfo); + begin + inherited create(aparent); + maxpushedparasize:=0; + end; + + + procedure tsparcprocinfo.allocate_push_parasize(size:longint); + begin + if size>maxpushedparasize then + maxpushedparasize:=size; + end; + + + function TSparcProcInfo.calc_stackframe_size:longint; + begin + { + Stackframe layout: + %fp + <locals> + <temp> + <arguments 6-n for calling> + %sp+92 + <space for arguments 0-5> \ + <return pointer for calling> | included in first_parm_offset + <register window save area for calling> / + %sp + + Alignment must be the max available, as doubles require + 8 byte alignment + } + result:=Align(tg.direction*tg.lasttemp+maxpushedparasize+target_info.first_parm_offset,aktalignment.localalignmax); + end; + + +begin + cprocinfo:=TSparcProcInfo; +end. diff --git a/compiler/sparc/cpuswtch.pas b/compiler/sparc/cpuswtch.pas new file mode 100644 index 0000000000..f94e8c080c --- /dev/null +++ b/compiler/sparc/cpuswtch.pas @@ -0,0 +1,125 @@ +{ + Copyright (c) 1998-2000 by Florian Klaempfl, Pierre Muller + + interprets the commandline options which are iSPARC specific + + 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 cpuswtch; + +{$INCLUDE fpcdefs.inc} + +interface + +uses + options; + +type + toptionSPARC=class(toption) + procedure interpret_proc_specific_options(const opt:string);override; + end; + +implementation + +uses + cutils,globtype,systems,globals,cpuinfo; + +procedure toptionSPARC.interpret_proc_specific_options(const opt:string); +var + j : longint; + More : string; +begin + More:=Upper(copy(opt,3,length(opt)-2)); + case opt[2] of + 'O' : Begin + j := 3; + While (j <= Length(Opt)) Do + Begin + case opt[j] of + '-' : + begin + initglobalswitches:=initglobalswitches-[cs_optimize,cs_fastoptimize,cs_slowoptimize,cs_littlesize, + cs_regvars,cs_uncertainopts]; + FillChar(ParaAlignment,sizeof(ParaAlignment),0); + end; + 'a' : + begin + UpdateAlignmentStr(Copy(Opt,j+1,255),ParaAlignment); + j:=length(Opt); + end; + 'g' : initglobalswitches:=initglobalswitches+[cs_littlesize]; + 'G' : initglobalswitches:=initglobalswitches-[cs_littlesize]; + 'r' : + begin + initglobalswitches:=initglobalswitches+[cs_regvars]; + Simplify_ppu:=false; + end; + 'u' : initglobalswitches:=initglobalswitches+[cs_uncertainopts]; + '1' : initglobalswitches:=initglobalswitches-[cs_fastoptimize,cs_slowoptimize]+[cs_optimize]; + '2' : initglobalswitches:=initglobalswitches-[cs_slowoptimize]+[cs_optimize,cs_fastoptimize]; + '3' : initglobalswitches:=initglobalswitches+[cs_optimize,cs_fastoptimize,cs_slowoptimize]; + 'p' : + Begin + If j < Length(Opt) Then + Begin + Case opt[j+1] Of + '1': initoptprocessor := SPARC_V8; + '2': initoptprocessor := SPARC_V9; + '3': initoptprocessor := SPARC_V9; + Else IllegalPara(Opt) + End; + Inc(j); + End + Else IllegalPara(opt) + End; +{$ifdef USECMOV} + 's' : + Begin + If j < Length(Opt) Then + Begin + Case opt[j+1] Of + '3': initspecificoptprocessor:=ClassP6 + Else IllegalPara(Opt) + End; + Inc(j); + End + Else IllegalPara(opt) + End +{$endif USECMOV} + else IllegalPara(opt); + End; + Inc(j) + end; + end; + 'R' : begin + if More='GAS' then + initasmmode:=asmmode_i386_att + else + if More='STANDARD' then + initasmmode:=asmmode_i386_intel + else + IllegalPara(opt); + end; + else + IllegalPara(opt); + end; +end; + + +initialization + coption:=toptionSPARC; +end. diff --git a/compiler/sparc/cputarg.pas b/compiler/sparc/cputarg.pas new file mode 100644 index 0000000000..a7b77c8467 --- /dev/null +++ b/compiler/sparc/cputarg.pas @@ -0,0 +1,76 @@ +{ + Copyright (c) 2001 by Peter Vreman + + Includes the i386 dependent target units + + 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 cputarg; + +{$i fpcdefs.inc} + +interface + + +implementation + + uses + systems { prevent a syntax error when nothing is included } + +{$ifndef NOOPT} + ,aoptcpu +{$endif NOOPT} + +{************************************** + Targets +**************************************} + + {$ifndef NOTARGETLINUX} + ,t_linux + {$endif} + {$ifndef NOTARGETSUNOS} + ,t_sunos + {$endif} + +{************************************** + Assemblers +**************************************} + + ,CpuGas + +{************************************** + Assembler Readers +**************************************} + + {$ifndef NoSparcgas} + ,racpugas + {$endif NoSparcgas} + +{************************************** + Debuginfo +**************************************} + + {$ifndef NoDbgStabs} + ,dbgstabs + {$endif NoDbgStabs} + {$ifndef NoDbgDwarf} + ,dbgdwarf + {$endif NoDbgDwarf} + + ; + +end. diff --git a/compiler/sparc/itcpugas.pas b/compiler/sparc/itcpugas.pas new file mode 100644 index 0000000000..c3a1ae4599 --- /dev/null +++ b/compiler/sparc/itcpugas.pas @@ -0,0 +1,98 @@ +{ + Copyright (c) 1998-2002 by Mazen NEIFER + + This unit contains the SPARC GAS instruction tables + + 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 itcpugas; + +{$i fpcdefs.inc} + +interface + + uses + cpubase,cgbase; + + const + gas_op2str : array[tasmop] of string[14] = ({$INCLUDE strinst.inc}); + + function gas_regnum_search(const s:string):Tregister; + function gas_regname(r:Tregister):string; + + +implementation + + uses + cutils,verbose; + + const + gas_regname_table : array[tregisterindex] of string[7] = ( + {$i rspstd.inc} + ); + + gas_regname_index : array[tregisterindex] of tregisterindex = ( + {$i rspsri.inc} + ); + + + function findreg_by_gasname(const s:string):tregisterindex; + var + i,p : tregisterindex; + begin + {Binary search.} + p:=0; + i:=regnumber_count_bsstart; + repeat + if (p+i<=high(tregisterindex)) and (gas_regname_table[gas_regname_index[p+i]]<=s) then + p:=p+i; + i:=i shr 1; + until i=0; + if gas_regname_table[gas_regname_index[p]]=s then + findreg_by_gasname:=gas_regname_index[p] + else + findreg_by_gasname:=0; + end; + + + function gas_regnum_search(const s:string):Tregister; + begin + result:=regnumber_table[findreg_by_gasname(s)]; + end; + + + function gas_regname(r:Tregister):string; + var + hr : tregister; + p : longint; + begin + { Double uses the same table as single } + hr:=r; + case getsubreg(hr) of + R_SUBFD: + setsubreg(hr,R_SUBFS); + R_SUBL,R_SUBW,R_SUBD,R_SUBQ: + setsubreg(hr,R_SUBD); + end; + p:=findreg_by_number(hr); + if p<>0 then + result:=gas_regname_table[p] + else + result:=generic_regname(r); + end; + +end. diff --git a/compiler/sparc/ncpuadd.pas b/compiler/sparc/ncpuadd.pas new file mode 100644 index 0000000000..413880988f --- /dev/null +++ b/compiler/sparc/ncpuadd.pas @@ -0,0 +1,376 @@ +{ + Copyright (c) 2000-2002 by Florian Klaempfl + + Code generation for add nodes on the SPARC + + 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 ncpuadd; + +{$i fpcdefs.inc} + +interface + + uses + node,ncgadd,cpubase; + + type + tsparcaddnode = class(tcgaddnode) + private + function GetResFlags(unsigned:Boolean):TResFlags; + function GetFPUResFlags:TResFlags; + protected + procedure second_addfloat;override; + procedure second_cmpfloat;override; + procedure second_cmpboolean;override; + procedure second_cmpsmallset;override; + procedure second_cmp64bit;override; + procedure second_cmpordinal;override; + end; + + implementation + + uses + systems, + cutils,verbose, + paramgr, + aasmtai,aasmcpu,defutil, + cgbase,cgcpu,cgutils, + cpupara, + ncon,nset,nadd, + ncgutil,cgobj; + +{***************************************************************************** + TSparcAddNode +*****************************************************************************} + + function TSparcAddNode.GetResFlags(unsigned:Boolean):TResFlags; + begin + case NodeType of + equaln: + GetResFlags:=F_E; + unequaln: + GetResFlags:=F_NE; + else + if not(unsigned) then + begin + if nf_swaped in flags then + case NodeType of + ltn: + GetResFlags:=F_G; + lten: + GetResFlags:=F_GE; + gtn: + GetResFlags:=F_L; + gten: + GetResFlags:=F_LE; + end + else + case NodeType of + ltn: + GetResFlags:=F_L; + lten: + GetResFlags:=F_LE; + gtn: + GetResFlags:=F_G; + gten: + GetResFlags:=F_GE; + end; + end + else + begin + if nf_swaped in Flags then + case NodeType of + ltn: + GetResFlags:=F_A; + lten: + GetResFlags:=F_AE; + gtn: + GetResFlags:=F_B; + gten: + GetResFlags:=F_BE; + end + else + case NodeType of + ltn: + GetResFlags:=F_B; + lten: + GetResFlags:=F_BE; + gtn: + GetResFlags:=F_A; + gten: + GetResFlags:=F_AE; + end; + end; + end; + end; + + + function TSparcAddNode.GetFPUResFlags:TResFlags; + begin + case NodeType of + equaln: + result:=F_FE; + unequaln: + result:=F_FNE; + else + begin + if nf_swaped in Flags then + case NodeType of + ltn: + result:=F_FG; + lten: + result:=F_FGE; + gtn: + result:=F_FL; + gten: + result:=F_FLE; + end + else + case NodeType of + ltn: + result:=F_FL; + lten: + result:=F_FLE; + gtn: + result:=F_FG; + gten: + result:=F_FGE; + end; + end; + end; + end; + + + procedure tsparcaddnode.second_addfloat; + var + op : TAsmOp; + begin + pass_left_right; + if (nf_swaped in flags) then + swapleftright; + + { force fpureg as location, left right doesn't matter + as both will be in a fpureg } + location_force_fpureg(exprasmlist,left.location,true); + location_force_fpureg(exprasmlist,right.location,(left.location.loc<>LOC_CFPUREGISTER)); + + location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def)); + if left.location.loc<>LOC_CFPUREGISTER then + location.register:=left.location.register + else + location.register:=right.location.register; + + case nodetype of + addn : + begin + if location.size=OS_F64 then + op:=A_FADDd + else + op:=A_FADDs; + end; + muln : + begin + if location.size=OS_F64 then + op:=A_FMULd + else + op:=A_FMULs; + end; + subn : + begin + if location.size=OS_F64 then + op:=A_FSUBd + else + op:=A_FSUBs; + end; + slashn : + begin + if location.size=OS_F64 then + op:=A_FDIVd + else + op:=A_FDIVs; + end; + else + internalerror(200306014); + end; + + exprasmlist.concat(taicpu.op_reg_reg_reg(op, + left.location.register,right.location.register,location.register)); + end; + + + procedure tsparcaddnode.second_cmpfloat; + var + op : tasmop; + begin + pass_left_right; + if (nf_swaped in flags) then + swapleftright; + + { force fpureg as location, left right doesn't matter + as both will be in a fpureg } + location_force_fpureg(exprasmlist,left.location,true); + location_force_fpureg(exprasmlist,right.location,true); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getfpuresflags; + + if left.location.size=OS_F64 then + op:=A_FCMPd + else + op:=A_FCMPs; + exprasmlist.concat(taicpu.op_reg_reg(op, + left.location.register,right.location.register)); + { Delay slot (can only contain integer operation) } + exprasmlist.concat(taicpu.op_none(A_NOP)); + end; + + + procedure tsparcaddnode.second_cmpboolean; + begin + pass_left_right; + force_reg_left_right(true,true); + + if right.location.loc = LOC_CONSTANT then + tcgsparc(cg).handle_reg_const_reg(exprasmlist,A_SUBcc,left.location.register,right.location.value,NR_G0) + else + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBcc,left.location.register,right.location.register,NR_G0)); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(true); + end; + + + procedure tsparcaddnode.second_cmpsmallset; + begin + pass_left_right; + force_reg_left_right(true,true); + + if right.location.loc = LOC_CONSTANT then + tcgsparc(cg).handle_reg_const_reg(exprasmlist,A_SUBcc,left.location.register,right.location.value,NR_G0) + else + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBcc,left.location.register,right.location.register,NR_G0)); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(true); + end; + + + procedure tsparcaddnode.second_cmp64bit; + var + unsigned : boolean; + + procedure firstjmp64bitcmp; + var + oldnodetype : tnodetype; + begin + { the jump the sequence is a little bit hairy } + case nodetype of + ltn,gtn: + begin + cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel); + { cheat a little bit for the negative test } + toggleflag(nf_swaped); + cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel); + toggleflag(nf_swaped); + end; + lten,gten: + begin + oldnodetype:=nodetype; + if nodetype=lten then + nodetype:=ltn + else + nodetype:=gtn; + cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel); + { cheat for the negative test } + if nodetype=ltn then + nodetype:=gtn + else + nodetype:=ltn; + cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel); + nodetype:=oldnodetype; + end; + equaln: + cg.a_jmp_flags(exprasmlist,F_NE,falselabel); + unequaln: + cg.a_jmp_flags(exprasmlist,F_NE,truelabel); + end; + end; + + procedure secondjmp64bitcmp; + + begin + { the jump the sequence is a little bit hairy } + case nodetype of + ltn,gtn,lten,gten: + begin + { the comparisaion of the low dword have to be } + { always unsigned! } + cg.a_jmp_flags(exprasmlist,getresflags(true),truelabel); + cg.a_jmp_always(exprasmlist,falselabel); + end; + equaln: + begin + cg.a_jmp_flags(exprasmlist,F_NE,falselabel); + cg.a_jmp_always(exprasmlist,truelabel); + end; + unequaln: + begin + cg.a_jmp_flags(exprasmlist,F_NE,truelabel); + cg.a_jmp_always(exprasmlist,falselabel); + end; + end; + end; + + begin + pass_left_right; + force_reg_left_right(false,false); + + unsigned:=not(is_signed(left.resulttype.def)) or + not(is_signed(right.resulttype.def)); + + location_reset(location,LOC_JUMP,OS_NO); + + exprasmlist.concat(taicpu.op_reg_reg(A_CMP,left.location.register64.reghi,right.location.register64.reghi)); + firstjmp64bitcmp; + exprasmlist.concat(taicpu.op_reg_reg(A_CMP,left.location.register64.reglo,right.location.register64.reglo)); + secondjmp64bitcmp; + end; + + + procedure tsparcaddnode.second_cmpordinal; + var + unsigned : boolean; + begin + pass_left_right; + force_reg_left_right(true,true); + + unsigned:=not(is_signed(left.resulttype.def)) or + not(is_signed(right.resulttype.def)); + + if right.location.loc = LOC_CONSTANT then + tcgsparc(cg).handle_reg_const_reg(exprasmlist,A_SUBcc,left.location.register,right.location.value,NR_G0) + else + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBcc,left.location.register,right.location.register,NR_G0)); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(unsigned); + end; + +begin + caddnode:=tsparcaddnode; +end. diff --git a/compiler/sparc/ncpucall.pas b/compiler/sparc/ncpucall.pas new file mode 100644 index 0000000000..343957ced8 --- /dev/null +++ b/compiler/sparc/ncpucall.pas @@ -0,0 +1,56 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generate sparc assembler for in call nodes + + 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 ncpucall; + +{$i fpcdefs.inc} + +interface + + uses + ncgcal; + + type + tsparccallnode = class(tcgcallnode) + procedure extra_post_call_code;override; + end; + + +implementation + + uses + cpubase, + aasmtai, + aasmcpu, + paramgr, + ncal; + + + procedure tsparccallnode.extra_post_call_code; + begin + if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then + exprasmlist.concat(taicpu.op_const(A_UNIMP,procdefinition.rettype.def.size and $fff)); + end; + + +begin + ccallnode:=TSparcCallNode; +end. diff --git a/compiler/sparc/ncpucnv.pas b/compiler/sparc/ncpucnv.pas new file mode 100644 index 0000000000..26df287315 --- /dev/null +++ b/compiler/sparc/ncpucnv.pas @@ -0,0 +1,305 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generate SPARC assembler for type converting nodes + + 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 ncpucnv; + +{$i fpcdefs.inc} + +interface + + uses + node,ncnv,ncgcnv,defcmp; + + type + tsparctypeconvnode = class(TCgTypeConvNode) + protected + { procedure second_int_to_int;override; } + { procedure second_string_to_string;override; } + { procedure second_cstring_to_pchar;override; } + { procedure second_string_to_chararray;override; } + { procedure second_array_to_pointer;override; } + function first_int_to_real: tnode; override; + { procedure second_pointer_to_array;override; } + { procedure second_chararray_to_string;override; } + { procedure second_char_to_string;override; } + procedure second_int_to_real;override; + procedure second_real_to_real;override; + { procedure second_cord_to_pointer;override; } + { procedure second_proc_to_procvar;override; } + { procedure second_bool_to_int;override; } + procedure second_int_to_bool;override; + { procedure second_load_smallset;override; } + { procedure second_ansistring_to_pchar;override; } + { procedure second_pchar_to_string;override; } + { procedure second_class_to_intf;override; } + { procedure second_char_to_char;override; } + end; + +implementation + + uses + verbose,globals,systems, + symconst,symdef,aasmbase,aasmtai, + defutil, + cgbase,cgutils,pass_1,pass_2, + ncon,ncal, + ncgutil, + cpubase,aasmcpu, + tgobj,cgobj; + + +{***************************************************************************** + FirstTypeConv +*****************************************************************************} + + function tsparctypeconvnode.first_int_to_real: tnode; + var + fname: string[19]; + begin + { converting a 64bit integer to a float requires a helper } + if is_64bitint(left.resulttype.def) or + is_currency(left.resulttype.def) then + begin + { hack to avoid double division by 10000, as it's + already done by resulttypepass.resulttype_int_to_real } + if is_currency(left.resulttype.def) then + left.resulttype := s64inttype; + if is_signed(left.resulttype.def) then + fname := 'fpc_int64_to_double' + else + fname := 'fpc_qword_to_double'; + result := ccallnode.createintern(fname,ccallparanode.create( + left,nil)); + left:=nil; + firstpass(result); + exit; + end + else + { other integers are supposed to be 32 bit } + begin + if is_signed(left.resulttype.def) then + inserttypeconv(left,s32inttype) + else + inserttypeconv(left,u32inttype); + firstpass(left); + end; + result := nil; + if registersfpu<1 then + registersfpu:=1; + expectloc:=LOC_FPUREGISTER; + end; + + +{***************************************************************************** + SecondTypeConv +*****************************************************************************} + + procedure tsparctypeconvnode.second_int_to_real; + + procedure loadsigned; + begin + location_force_mem(exprasmlist,left.location); + { Load memory in fpu register } + cg.a_loadfpu_ref_reg(exprasmlist,OS_F32,left.location.reference,location.register); + tg.ungetiftemp(exprasmlist,left.location.reference); + { Convert value in fpu register from integer to float } + case tfloatdef(resulttype.def).typ of + s32real: + exprasmlist.concat(taicpu.op_reg_reg(A_FiTOs,location.register,location.register)); + s64real: + exprasmlist.concat(taicpu.op_reg_reg(A_FiTOd,location.register,location.register)); + s128real: + exprasmlist.concat(taicpu.op_reg_reg(A_FiTOq,location.register,location.register)); + else + internalerror(200408011); + end; + end; + + var + href : treference; + hregister : tregister; + l1,l2 : tasmlabel; + + begin + location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def)); + if is_signed(left.resulttype.def) then + begin + location.register:=cg.getfpuregister(exprasmlist,location.size); + loadsigned; + end + else + begin + objectlibrary.getdatalabel(l1); + objectlibrary.getjumplabel(l2); + reference_reset_symbol(href,l1,0); + hregister:=cg.getintregister(exprasmlist,OS_32); + cg.a_load_loc_reg(exprasmlist,OS_32,left.location,hregister); + + { here we need always an 64 bit register } + location.register:=cg.getfpuregister(exprasmlist,OS_F64); + location_force_mem(exprasmlist,left.location); + { Load memory in fpu register } + cg.a_loadfpu_ref_reg(exprasmlist,OS_F32,left.location.reference,location.register); + tg.ungetiftemp(exprasmlist,left.location.reference); + exprasmlist.concat(taicpu.op_reg_reg(A_FiTOd,location.register,location.register)); + + exprasmList.concat(Taicpu.op_reg_reg(A_CMP,hregister,NR_G0)); + cg.a_jmp_flags(exprasmlist,F_GE,l2); + + case tfloatdef(resulttype.def).typ of + { converting dword to s64real first and cut off at the end avoids precision loss } + s32real, + s64real: + begin + hregister:=cg.getfpuregister(exprasmlist,OS_F64); + asmlist[al_typedconsts].concat(tai_align.create(const_align(8))); + asmlist[al_typedconsts].concat(Tai_label.Create(l1)); + { I got this constant from a test program (FK) } + asmlist[al_typedconsts].concat(Tai_const.Create_32bit($41f00000)); + asmlist[al_typedconsts].concat(Tai_const.Create_32bit(0)); + + cg.a_loadfpu_ref_reg(exprasmlist,OS_F64,href,hregister); + exprasmlist.concat(taicpu.op_reg_reg_reg(A_FADDD,location.register,hregister,location.register)); + cg.a_label(exprasmlist,l2); + + { cut off if we should convert to single } + if tfloatdef(resulttype.def).typ=s32real then + begin + hregister:=location.register; + location.register:=cg.getfpuregister(exprasmlist,location.size); + exprasmlist.concat(taicpu.op_reg_reg(A_FDTOS,hregister,location.register)); + end; + end; + else + internalerror(200410031); + end; + end; + end; + + + procedure tsparctypeconvnode.second_real_to_real; + const + conv_op : array[tfloattype,tfloattype] of tasmop = ( + { from: s32 s64 s80 c64 cur f128 } + { s32 } ( A_FMOVS,A_FDTOS,A_NONE, A_NONE, A_NONE, A_NONE ), + { s64 } ( A_FSTOD,A_FMOVD,A_NONE, A_NONE, A_NONE, A_NONE ), + { s80 } ( A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE ), + { c64 } ( A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE ), + { cur } ( A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE ), + { f128 } ( A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE ) + ); + var + op : tasmop; + begin + location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def)); + location_force_fpureg(exprasmlist,left.location,false); + { Convert value in fpu register from integer to float } + op:=conv_op[tfloatdef(resulttype.def).typ,tfloatdef(left.resulttype.def).typ]; + if op=A_NONE then + internalerror(200401121); + location.register:=cg.getfpuregister(exprasmlist,location.size); + exprasmlist.concat(taicpu.op_reg_reg(op,left.location.register,location.register)); + end; + + + procedure tsparctypeconvnode.second_int_to_bool; + var + hreg1,hreg2 : tregister; + resflags : tresflags; + opsize : tcgsize; + hlabel,oldtruelabel,oldfalselabel : tasmlabel; + begin + oldtruelabel:=truelabel; + oldfalselabel:=falselabel; + objectlibrary.getjumplabel(truelabel); + objectlibrary.getjumplabel(falselabel); + secondpass(left); + if codegenerror then + exit; + + { byte(boolean) or word(wordbool) or longint(longbool) must } + { be accepted for var parameters } + if (nf_explicit in flags)and + (left.resulttype.def.size=resulttype.def.size)and + (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then + begin + location_copy(location,left.location); + truelabel:=oldtruelabel; + falselabel:=oldfalselabel; + exit; + end; + location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def)); + opsize:=def_cgsize(left.resulttype.def); + case left.location.loc of + LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER: + begin + if left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then + begin + hreg2:=cg.getintregister(exprasmlist,opsize); + cg.a_load_ref_reg(exprasmlist,opsize,opsize,left.location.reference,hreg2); + end + else + hreg2:=left.location.register; +{$ifndef cpu64bit} + if left.location.size in [OS_64,OS_S64] then + begin + hreg1:=cg.getintregister(exprasmlist,OS_32); + cg.a_op_reg_reg_reg(exprasmlist,OP_OR,OS_32,hreg2,tregister(succ(longint(hreg2))),hreg1); + hreg2:=hreg1; + opsize:=OS_32; + end; +{$endif cpu64bit} + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBCC,NR_G0,hreg2,NR_G0)); + hreg1:=cg.getintregister(exprasmlist,opsize); + exprasmlist.concat(taicpu.op_reg_const_reg(A_ADDX,NR_G0,0,hreg1)); + end; + LOC_FLAGS : + begin + hreg1:=cg.GetIntRegister(exprasmlist,location.size); + resflags:=left.location.resflags; + cg.g_flags2reg(exprasmlist,location.size,resflags,hreg1); + end; + LOC_JUMP : + begin + hreg1:=cg.getintregister(exprasmlist,OS_INT); + objectlibrary.getjumplabel(hlabel); + cg.a_label(exprasmlist,truelabel); + cg.a_load_const_reg(exprasmlist,OS_INT,1,hreg1); + cg.a_jmp_always(exprasmlist,hlabel); + cg.a_label(exprasmlist,falselabel); + cg.a_load_const_reg(exprasmlist,OS_INT,0,hreg1); + cg.a_label(exprasmlist,hlabel); + end; + else + internalerror(10062); + end; + location.register:=hreg1; + + if location.size in [OS_64, OS_S64] then + internalerror(200408241); + + truelabel:=oldtruelabel; + falselabel:=oldfalselabel; + end; + + +begin + ctypeconvnode:=tsparctypeconvnode; +end. diff --git a/compiler/sparc/ncpuinln.pas b/compiler/sparc/ncpuinln.pas new file mode 100644 index 0000000000..4e3dfb7fdc --- /dev/null +++ b/compiler/sparc/ncpuinln.pas @@ -0,0 +1,149 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generate SPARC inline nodes + + 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 ncpuinln; + +{$i fpcdefs.inc} + +interface + + uses + node,ninl,ncginl; + + type + tsparcinlinenode = class(tcgInlineNode) + function first_abs_real: tnode; override; + function first_sqr_real: tnode; override; + function first_sqrt_real: tnode; override; + procedure second_abs_real; override; + procedure second_sqr_real; override; + procedure second_sqrt_real; override; + private + procedure load_fpu_location; + end; + + +implementation + + uses + systems, + cutils,verbose, + symconst,symdef, + aasmtai,aasmcpu, + cgbase,pass_2, + cpubase,paramgr, + nbas,ncon,ncal,ncnv,nld, + ncgutil,cgobj,cgutils; + +{***************************************************************************** + tsparcinlinenode +*****************************************************************************} + + procedure tsparcinlinenode.load_fpu_location; + begin + secondpass(left); + location_force_fpureg(exprasmlist,left.location,true); + location_copy(location,left.location); + if left.location.loc=LOC_CFPUREGISTER then + begin + location.register:=cg.getfpuregister(exprasmlist,location.size); + location.loc := LOC_FPUREGISTER; + end; + end; + + + function tsparcinlinenode.first_abs_real : tnode; + begin + expectloc:=LOC_FPUREGISTER; + registersint:=left.registersint; + registersfpu:=max(left.registersfpu,1); + first_abs_real := nil; + end; + + + function tsparcinlinenode.first_sqr_real : tnode; + begin + expectloc:=LOC_FPUREGISTER; + registersint:=left.registersint; + registersfpu:=max(left.registersfpu,1); + first_sqr_real:=nil; + end; + + + function tsparcinlinenode.first_sqrt_real : tnode; + begin + expectloc:=LOC_FPUREGISTER; + registersint:=left.registersint; + registersfpu:=max(left.registersfpu,1); + first_sqrt_real := nil; + end; + + + procedure tsparcinlinenode.second_abs_real; + begin + load_fpu_location; + case tfloatdef(left.resulttype.def).typ of + s32real: + exprasmlist.concat(taicpu.op_reg_reg(A_FABSs,left.location.register,location.register)); + s64real: + exprasmlist.concat(taicpu.op_reg_reg(A_FABSd,left.location.register,location.register)); + s128real: + exprasmlist.concat(taicpu.op_reg_reg(A_FABSq,left.location.register,location.register)); + else + internalerror(200410031); + end; + end; + + + procedure tsparcinlinenode.second_sqr_real; + begin + load_fpu_location; + case tfloatdef(left.resulttype.def).typ of + s32real: + exprasmlist.concat(taicpu.op_reg_reg_reg(A_FMULs,left.location.register,left.location.register,location.register)); + s64real: + exprasmlist.concat(taicpu.op_reg_reg_reg(A_FMULd,left.location.register,left.location.register,location.register)); + s128real: + exprasmlist.concat(taicpu.op_reg_reg_reg(A_FMULq,left.location.register,left.location.register,location.register)); + else + internalerror(200410032); + end; + end; + + + procedure tsparcinlinenode.second_sqrt_real; + begin + load_fpu_location; + case tfloatdef(left.resulttype.def).typ of + s32real: + exprasmlist.concat(taicpu.op_reg_reg(A_FSQRTs,left.location.register,location.register)); + s64real: + exprasmlist.concat(taicpu.op_reg_reg(A_FSQRTd,left.location.register,location.register)); + s128real: + exprasmlist.concat(taicpu.op_reg_reg(A_FSQRTq,left.location.register,location.register)); + else + internalerror(200410033); + end; + end; + +begin + cInlineNode:=tsparcinlinenode; +end. diff --git a/compiler/sparc/ncpumat.pas b/compiler/sparc/ncpumat.pas new file mode 100644 index 0000000000..34879d9790 --- /dev/null +++ b/compiler/sparc/ncpumat.pas @@ -0,0 +1,324 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generate SPARC assembler for math nodes + + 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 ncpumat; + +{$i fpcdefs.inc} + +interface + + uses + node,nmat,ncgmat; + + type + tSparcmoddivnode = class(tmoddivnode) + procedure pass_2;override; + end; + + tSparcshlshrnode = class(tshlshrnode) + procedure pass_2;override; + { everything will be handled in pass_2 } + function first_shlshr64bitint: tnode; override; + end; + + tSparcnotnode = class(tcgnotnode) + procedure second_boolean;override; + end; + +implementation + + uses + globtype,systems, + cutils,verbose,globals, + symconst, + aasmbase,aasmcpu,aasmtai, + defutil, + cgbase,cgobj,pass_2, + ncon, + cpubase, + ncgutil,cgcpu,cgutils; + +{***************************************************************************** + TSparcMODDIVNODE +*****************************************************************************} + + procedure tSparcmoddivnode.pass_2; + const + { signed overflow } + divops: array[boolean, boolean] of tasmop = + ((A_UDIV,A_UDIVcc),(A_SDIV,A_SDIVcc)); + var + power : longint; + op : tasmop; + tmpreg, + numerator, + divider, + resultreg : tregister; + overflowlabel : tasmlabel; + ai : taicpu; + begin + secondpass(left); + secondpass(right); + location_copy(location,left.location); + + { put numerator in register } + location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),true); + location_copy(location,left.location); + numerator := location.register; + + if (nodetype = modn) then + resultreg := cg.GetIntRegister(exprasmlist,OS_INT) + else + begin + if (location.loc = LOC_CREGISTER) then + begin + location.loc := LOC_REGISTER; + location.register := cg.GetIntRegister(exprasmlist,OS_INT); + end; + resultreg := location.register; + end; + + if (nodetype = divn) and + (right.nodetype = ordconstn) and + ispowerof2(tordconstnode(right).value,power) then + begin + tmpreg:=cg.GetIntRegister(exprasmlist,OS_INT); + cg.a_op_const_reg_reg(exprasmlist,OP_SAR,OS_INT,31,numerator,tmpreg); + { if signed, tmpreg=right value-1, otherwise 0 } + cg.a_op_const_reg(exprasmlist,OP_AND,OS_INT,tordconstnode(right).value-1,tmpreg); + { add to the left value } + cg.a_op_reg_reg(exprasmlist,OP_ADD,OS_INT,tmpreg,numerator); + cg.a_op_const_reg_reg(exprasmlist,OP_SAR,OS_INT,aword(power),numerator,resultreg); + end + else + begin + { load divider in a register if necessary } + location_force_reg(exprasmlist,right.location, + def_cgsize(right.resulttype.def),true); + divider := right.location.register; + + { needs overflow checking, (-maxlongint-1) div (-1) overflows! } + { And on Sparc, the only way to catch a div-by-0 is by checking } + { the overflow flag (JM) } + + { Fill %y with the -1 or 0 depending on the highest bit } + if is_signed(left.resulttype.def) then + begin + tmpreg:=cg.GetIntRegister(exprasmlist,OS_INT); + exprasmlist.concat(taicpu.op_reg_const_reg(A_SRA,numerator,31,tmpreg)); + exprasmlist.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_Y)); + end + else + exprasmlist.concat(taicpu.op_reg_reg(A_MOV,NR_G0,NR_Y)); + { wait 3 instructions slots before we can read %y } + exprasmlist.concat(taicpu.op_none(A_NOP)); + exprasmlist.concat(taicpu.op_none(A_NOP)); + exprasmlist.concat(taicpu.op_none(A_NOP)); + + op := divops[is_signed(right.resulttype.def), + cs_check_overflow in aktlocalswitches]; + exprasmlist.concat(taicpu.op_reg_reg_reg(op,numerator,divider,resultreg)); + + if (nodetype = modn) then + begin + objectlibrary.getjumplabel(overflowlabel); + ai:=taicpu.op_cond_sym(A_Bxx,C_O,overflowlabel); + ai.delayslot_annulled:=true; + exprasmlist.concat(ai); + exprasmlist.concat(taicpu.op_reg(A_NOT,resultreg)); + cg.a_label(exprasmlist,overflowlabel); + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SMUL,resultreg,divider,resultreg)); + exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUB,numerator,resultreg,resultreg)); + end; + end; + { set result location } + location.loc:=LOC_REGISTER; + location.register:=resultreg; + cg.g_overflowcheck(exprasmlist,Location,ResultType.Def); + end; + + +{***************************************************************************** + TSparcSHLRSHRNODE +*****************************************************************************} + + function TSparcShlShrNode.first_shlshr64bitint:TNode; + begin + { 64bit without constants need a helper } + if is_64bit(left.resulttype.def) and + (right.nodetype<>ordconstn) then + begin + result:=inherited first_shlshr64bitint; + exit; + end; + + result := nil; + end; + + + procedure tSparcshlshrnode.pass_2; + var + hregister,resultreg,hregister1, + hreg64hi,hreg64lo : tregister; + op : topcg; + shiftval: aword; + begin + { 64bit without constants need a helper, and is + already replaced in pass1 } + if is_64bit(left.resulttype.def) and + (right.nodetype<>ordconstn) then + internalerror(200405301); + + secondpass(left); + secondpass(right); + if is_64bit(left.resulttype.def) then + begin + location_reset(location,LOC_REGISTER,OS_64); + + { load left operator in a register } + location_force_reg(exprasmlist,left.location,OS_64,false); + hreg64hi:=left.location.register64.reghi; + hreg64lo:=left.location.register64.reglo; + + shiftval := tordconstnode(right).value and 63; + if shiftval > 31 then + begin + if nodetype = shln then + begin + cg.a_load_const_reg(exprasmlist,OS_32,0,hreg64hi); + if (shiftval and 31) <> 0 then + cg.a_op_const_reg_reg(exprasmlist,OP_SHL,OS_32,shiftval and 31,hreg64lo,hreg64lo); + end + else + begin + cg.a_load_const_reg(exprasmlist,OS_32,0,hreg64lo); + if (shiftval and 31) <> 0 then + cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_32,shiftval and 31,hreg64hi,hreg64hi); + end; + location.register64.reglo:=hreg64hi; + location.register64.reghi:=hreg64lo; + end + else + begin + hregister:=cg.getintregister(exprasmlist,OS_32); + if nodetype = shln then + begin + cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_32,32-shiftval,hreg64lo,hregister); + cg.a_op_const_reg_reg(exprasmlist,OP_SHL,OS_32,shiftval,hreg64hi,hreg64hi); + cg.a_op_reg_reg_reg(exprasmlist,OP_OR,OS_32,hregister,hreg64hi,hreg64hi); + cg.a_op_const_reg_reg(exprasmlist,OP_SHL,OS_32,shiftval,hreg64lo,hreg64lo); + end + else + begin + cg.a_op_const_reg_reg(exprasmlist,OP_SHL,OS_32,32-shiftval,hreg64hi,hregister); + cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_32,shiftval,hreg64lo,hreg64lo); + cg.a_op_reg_reg_reg(exprasmlist,OP_OR,OS_32,hregister,hreg64lo,hreg64lo); + cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_32,shiftval,hreg64hi,hreg64hi); + end; + location.register64.reghi:=hreg64hi; + location.register64.reglo:=hreg64lo; + end; + end + else + begin + { load left operators in a register } + location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),true); + location_copy(location,left.location); + resultreg := location.register; + hregister1 := location.register; + if (location.loc = LOC_CREGISTER) then + begin + location.loc := LOC_REGISTER; + resultreg := cg.GetIntRegister(exprasmlist,OS_INT); + location.register := resultreg; + end; + { determine operator } + if nodetype=shln then + op:=OP_SHL + else + op:=OP_SHR; + { shifting by a constant directly coded: } + if (right.nodetype=ordconstn) then + begin + if tordconstnode(right).value and 31<>0 then + cg.a_op_const_reg_reg(exprasmlist,op,OS_32,tordconstnode(right).value and 31,hregister1,resultreg) + end + else + begin + { load shift count in a register if necessary } + location_force_reg(exprasmlist,right.location,def_cgsize(right.resulttype.def),true); + cg.a_op_reg_reg_reg(exprasmlist,op,OS_32,right.location.register,hregister1,resultreg); + end; + end; + end; + + +{***************************************************************************** + TSPARCNOTNODE +*****************************************************************************} + + procedure tsparcnotnode.second_boolean; + var + hl : tasmlabel; + begin + { if the location is LOC_JUMP, we do the secondpass after the + labels are allocated + } + if left.expectloc=LOC_JUMP then + begin + hl:=truelabel; + truelabel:=falselabel; + falselabel:=hl; + secondpass(left); + maketojumpbool(exprasmlist,left,lr_load_regvars); + hl:=truelabel; + truelabel:=falselabel; + falselabel:=hl; + location.loc:=LOC_JUMP; + end + else + begin + secondpass(left); + case left.location.loc of + LOC_FLAGS : + begin + location_copy(location,left.location); + inverse_flags(location.resflags); + end; + LOC_REGISTER, LOC_CREGISTER, LOC_REFERENCE, LOC_CREFERENCE : + begin + location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),true); + exprasmlist.concat(taicpu.op_reg_const_reg(A_SUBcc,left.location.register,0,NR_G0)); + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=F_E; + end; + else + internalerror(2003042401); + end; + end; + end; + + +begin + cmoddivnode:=tSparcmoddivnode; + cshlshrnode:=tSparcshlshrnode; + cnotnode:=tSparcnotnode; +end. diff --git a/compiler/sparc/ncpuset.pas b/compiler/sparc/ncpuset.pas new file mode 100644 index 0000000000..6f0b955859 --- /dev/null +++ b/compiler/sparc/ncpuset.pas @@ -0,0 +1,126 @@ +{ + Copyright (c) 1998-2004 by Florian Klaempfl + + Generate sparc assembler for in set/case nodes + + 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 ncpuset; + +{$i fpcdefs.inc} + + interface + + uses + globtype, + nset, + ncgset; + + type + tcpucasenode = class(tcgcasenode) + protected + procedure optimizevalues(var max_linear_list:aint;var max_dist:aword);override; + function has_jumptable : boolean;override; + procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override; + end; + + + implementation + + uses + globals, + systems, + cpubase, + aasmbase,aasmtai,aasmcpu, + cgbase,cgutils,cgobj, + procinfo; + + procedure tcpucasenode.optimizevalues(var max_linear_list:aint;var max_dist:aword); + begin + { give the jump table a higher priority } + max_dist:=(max_dist*3) div 2; + end; + + + function tcpucasenode.has_jumptable : boolean; + begin + has_jumptable:=true; + end; + + + procedure tcpucasenode.genjumptable(hp : pcaselabel;min_,max_ : aint); + var + table : tasmlabel; + last : TConstExprInt; + indexreg,jmpreg,basereg : tregister; + href : treference; + + procedure genitem(list:taasmoutput;t : pcaselabel); + var + i : aint; + begin + if assigned(t^.less) then + genitem(list,t^.less); + { fill possible hole } + for i:=last+1 to t^._low-1 do + list.concat(Tai_const.Create_sym(elselabel)); + for i:=t^._low to t^._high do + list.concat(Tai_const.Create_sym(blocklabel(t^.blockid))); + last:=t^._high; + if assigned(t^.greater) then + genitem(list,t^.greater); + end; + + begin + if not(jumptable_no_range) then + begin + { case expr less than min_ => goto elselabel } + cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aint(min_),hregister,elselabel); + { case expr greater than max_ => goto elselabel } + cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_gt,aint(max_),hregister,elselabel); + end; + objectlibrary.getjumplabel(table); + indexreg:=cg.getaddressregister(exprasmlist); + cg.a_op_const_reg_reg(exprasmlist,OP_SHL,OS_ADDR,2,hregister,indexreg); + { create reference } + reference_reset_symbol(href,table,0); + href.offset:=(-aint(min_))*4; + basereg:=cg.getaddressregister(exprasmlist); + cg.a_loadaddr_ref_reg(exprasmlist,href,basereg); + + jmpreg:=cg.getaddressregister(exprasmlist); + + reference_reset(href); + href.index:=indexreg; + href.base:=basereg; + cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,jmpreg); + + exprasmlist.concat(taicpu.op_reg(A_JMP,jmpreg)); + { Delay slot } + exprasmlist.concat(taicpu.op_none(A_NOP)); + { generate jump table } + new_section(current_procinfo.aktlocaldata,sec_data,current_procinfo.procdef.mangledname,sizeof(aint)); + current_procinfo.aktlocaldata.concat(Tai_label.Create(table)); + last:=min_; + genitem(current_procinfo.aktlocaldata,hp); + end; + + + +begin + ccasenode:=tcpucasenode; +end. diff --git a/compiler/sparc/opcode.inc b/compiler/sparc/opcode.inc new file mode 100644 index 0000000000..a3b38b4f08 --- /dev/null +++ b/compiler/sparc/opcode.inc @@ -0,0 +1,73 @@ +{****************************************************************************** + *****************************************************************************} +A_NONE, +A_ABCD, +A_ADD,A_ADDcc,A_ADDX,A_ADDXcc, +A_AND,A_ANDcc,A_ANDN,A_ANDNcc, +{Branching instructions} +A_JMP, +A_JMPL, +A_CALL, +A_BA,A_Bxx,A_FBA,A_FBxx, +A_CBccc, +A_FLUSH, +{Load instructions} +A_LDSB,A_LDSH,A_LDSTUB, +A_LDUB,A_LDUH,A_LD,A_LDD,A_LDF,A_LDFSR,A_LDDF,A_LDC,A_LDCSR,A_LDDC, +A_LDSBA,A_LDSHA,A_LDUBA,A_LDUHA,A_LDA,A_LDDA, +A_LDSTUBA, +A_MULScc, +A_NOP, +A_OR,A_ORcc,A_ORN,A_ORNcc, +A_RDASR,A_RDY,A_RDPSR,A_RDWIM,A_RDTBR, +A_RESTORE, +A_RET,A_RETL, +A_SAVE, +A_SDIV,A_SDIVcc, +A_SMUL,A_SMULcc, +A_SETHI, +A_SLL,A_SRL,A_SRA, +A_STB,A_STH,A_ST,A_STD,A_STF,A_STDF,A_STFSR,A_STDFQ, +A_STC,A_STDC,A_STCSR,A_STDCQ, +A_STBA,A_STHA,A_STA,A_STDA, +A_SUB,A_SUBcc,A_SUBX,A_SUBXcc, +A_SWAP,A_SWAPA,A_Ticc,A_TADDcc,A_TSUBcc,A_TADDccTV,A_TSUBccTV, +A_TA,A_Txx, +A_UDIV,A_UDIVcc, +A_UMUL,A_UMULcc, +A_UNIMP, +A_WRASR,A_WRY,A_WRPSR,A_WRWIM,A_WRTBR, +A_XNOR,A_XNORcc, +A_XOR,A_XORcc, + {Floating-point instructions} +A_FiTOs,A_FiTOd,A_FiTOq, +A_FsTOi,A_FdTOi,A_FqTOi, +A_FsTOd,A_FsTOq, +A_FdTOs,A_FdTOq, +A_FqTOd,A_FqTOs, +A_FMOVs,A_FNEGs,A_FABSs, +A_FSQRTs,A_FSQRTd,A_FSQRTq, +A_FADDs,A_FADDd,A_FADDq, +A_FSUBs,A_FSUBd,A_FSUBq, +A_FMULs,A_FMULd,A_FMULQ, +A_FdMULq,A_FsMULd, +A_FDIVs,A_FDIVd,A_FDIVq, +A_FCMPs,A_FCMPd,A_FCMPq, +A_FCPop1,A_CPop2, + {Synthetic instructions} +A_btst,A_bset,A_bclr,A_btog, +A_clr,A_clrb,A_clrh, +A_cmp, +A_dec,A_deccc, +A_inc,A_inccc, +A_MOV, +A_NEG, +A_not, +A_set, +A_skipz,A_skipnz, +A_tst, +{ Internal instructions } +A_FMOVd, +A_FABSd, +A_FABSq + diff --git a/compiler/sparc/racpu.pas b/compiler/sparc/racpu.pas new file mode 100644 index 0000000000..92b4bbce3a --- /dev/null +++ b/compiler/sparc/racpu.pas @@ -0,0 +1,53 @@ +{ + Copyright (c) 1998-2003 by Mazen NEIFER + + Handles the common Sparc assembler reader routines + + 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 racpu; + +{$i fpcdefs.inc} + +interface + + uses + aasmbase,aasmtai,aasmcpu, + cpubase,rautils,cclasses; + + type + TSparcOperand=class(TOperand) + end; + + TSparcInstruction=class(TInstruction) + delayslot_annulled : boolean; + { opcode adding } + function ConcatInstruction(p : taasmoutput) : tai;override; + end; + +implementation + + function TSparcInstruction.ConcatInstruction(p : taasmoutput) : tai; + begin + result:=inherited ConcatInstruction(p); + { delay slot annulled support } + if (result.typ=ait_instruction) and + delayslot_annulled then + taicpu(result).delayslot_annulled:=true; + end; + +end. diff --git a/compiler/sparc/racpugas.pas b/compiler/sparc/racpugas.pas new file mode 100644 index 0000000000..818c36b9a7 --- /dev/null +++ b/compiler/sparc/racpugas.pas @@ -0,0 +1,671 @@ +{ + Copyright (c) 1998-2002 by Mazen NEIFER + + Does the parsing for the i386 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 + raatt,racpu; + + type + tSparcReader = class(tattreader) + function is_asmopcode(const s: string):boolean;override; + procedure handleopcode;override; + procedure BuildReference(oper : tSparcoperand); + procedure BuildOperand(oper : tSparcoperand); + procedure BuildOpCode(instr : tSparcinstruction); + procedure ReadPercent(oper : tSparcoperand); + procedure ReadSym(oper : tSparcoperand); + procedure ConvertCalljmp(instr : tSparcinstruction); + procedure handlepercent;override; + end; + + + Implementation + + uses + { helpers } + cutils, + { global } + globtype,verbose, + systems, + { aasm } + cpubase,aasmbase,aasmtai,aasmcpu, + { symtable } + symconst,symsym, + { parser } + scanner, + procinfo, + rabase,rautils, + cgbase,cgobj + ; + + procedure TSparcReader.ReadSym(oper : tSparcoperand); + var + tempstr : string; + typesize,l,k : aint; + begin + tempstr:=actasmpattern; + Consume(AS_ID); + { typecasting? } + if (actasmtoken=AS_LPAREN) and + SearchType(tempstr,typesize) then + begin + oper.hastype:=true; + Consume(AS_LPAREN); + BuildOperand(oper); + Consume(AS_RPAREN); + if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then + oper.SetSize(typesize,true); + end + else + if not oper.SetupVar(tempstr,false) then + Message1(sym_e_unknown_id,tempstr); + { record.field ? } + if actasmtoken=AS_DOT then + begin + BuildRecordOffsetSize(tempstr,l,k); + inc(oper.opr.ref.offset,l); + end; + end; + + + procedure TSparcReader.ReadPercent(oper : tSparcoperand); + begin + { check for ...@ } + if actasmtoken=AS_AT then + begin + if (oper.opr.ref.symbol=nil) and + (oper.opr.ref.offset = 0) then + Message(asmr_e_invalid_reference_syntax); + Consume(AS_AT); + if actasmtoken=AS_ID then + begin + if upper(actasmpattern)='LO' then + oper.opr.ref.refaddr:=addr_lo + else if upper(actasmpattern)='HI' then + oper.opr.ref.refaddr:=addr_hi + else + Message(asmr_e_invalid_reference_syntax); + Consume(AS_ID); + end + else + Message(asmr_e_invalid_reference_syntax); + end; + end; + + + Procedure TSparcReader.BuildReference(oper : tSparcoperand); + var + l : aint; + regs : byte; + hasimm : boolean; + begin + oper.initref; + regs:=0; + hasimm:=false; + Consume(AS_LBRACKET); + repeat + Case actasmtoken of + AS_INTNUM, + AS_MINUS, + AS_PLUS: + Begin + if hasimm or (regs>1) then + Begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(true); + break; + End; + oper.opr.Ref.Offset:=BuildConstExpression(false,true); + hasimm:=true; + End; + + AS_REGISTER: + Begin + if regs<2 then + begin + if regs=0 then + oper.opr.ref.base:=actasmregister + else + oper.opr.ref.index:=actasmregister; + inc(regs); + end + else + begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(true); + break; + end; + Consume(AS_REGISTER); + end; + + AS_ID: + Begin + l:=BuildConstExpression(true,true); + inc(oper.opr.ref.offset,l); + End; + + AS_RBRACKET: + begin + if (regs=0) and (not hasimm) then + Message(asmr_e_invalid_reference_syntax); + Consume(AS_RBRACKET); + break; + end; + + else + Begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + break; + end; + end; + until false; + end; + + + procedure TSparcReader.handlepercent; + var + len : longint; + begin + len:=1; + actasmpattern[len]:='%'; + c:=current_scanner.asmgetchar; + { to be a register there must be a letter and not a number } + 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); + uppervar(actasmpattern); + if is_register(actasmpattern) then + exit; + if (actasmpattern='%HI') then + actasmtoken:=AS_HI + else if (actasmpattern='%LO')then + actasmtoken:=AS_LO + else + Message(asmr_e_invalid_register); + end; + + + Procedure TSparcReader.BuildOperand(oper : tSparcoperand); + var + expr : string; + typesize,l : aint; + + procedure AddLabelOperand(hl:tasmlabel); + begin + if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and + is_calljmp(actopcode) then + begin + oper.opr.typ:=OPR_SYMBOL; + oper.opr.symbol:=hl; + end + else + begin + oper.InitRef; + oper.opr.ref.symbol:=hl; + end; + end; + + + procedure MaybeRecordOffset; + var + hasdot : boolean; + l, + toffset, + tsize : aint; + begin + if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then + exit; + l:=0; + hasdot:=(actasmtoken=AS_DOT); + if hasdot then + begin + if expr<>'' then + begin + BuildRecordOffsetSize(expr,toffset,tsize); + inc(l,toffset); + oper.SetSize(tsize,true); + end; + end; + if actasmtoken in [AS_PLUS,AS_MINUS] then + inc(l,BuildConstExpression(true,false)); + case oper.opr.typ of + OPR_LOCAL : + begin + { don't allow direct access to fields of parameters, because that + will generate buggy code. Allow it only for explicit typecasting } + if hasdot and + (not oper.hastype) and + (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and + (current_procinfo.procdef.proccalloption<>pocall_register) then + Message(asmr_e_cannot_access_field_directly_for_parameters); + inc(oper.opr.localsymofs,l) + end; + OPR_CONSTANT : + inc(oper.opr.val,l); + OPR_REFERENCE : + inc(oper.opr.ref.offset,l); + else + internalerror(200309221); + end; + end; + + var + tempreg : tregister; + tempstr : string; + tempsymtyp : TAsmSymType; + hl : tasmlabel; + gotplus, + negative : boolean; + Begin + expr:=''; + gotplus:=true; + negative:=false; + repeat + case actasmtoken of + AS_MINUS : + begin + consume(AS_MINUS); + negative:=true; + gotplus:=true; + end; + + AS_PLUS : + begin + consume(AS_PLUS); + negative:=false; + gotplus:=true; + end; + + AS_INTNUM, + AS_MOD: + Begin + if not gotplus then + Message(asmr_e_invalid_reference_syntax); + l:=BuildConstExpression(True,False); + if negative then + l:=-l; + { Constant memory offset } + oper.InitRef; + oper.opr.ref.refaddr:=addr_full; + oper.opr.ref.offset:=l; + GotPlus:=(prevasmtoken=AS_PLUS) or + (prevasmtoken=AS_MINUS); + if GotPlus then + negative:=(prevasmtoken=AS_MINUS); + end; + + AS_LBRACKET : + begin + { memory reference } + BuildReference(oper); + gotplus:=false; + end; + + AS_HI, + AS_LO: + begin + { Low or High part of a constant (or constant + memory location) } + oper.InitRef; + if actasmtoken=AS_LO then + oper.opr.ref.refaddr:=addr_lo + else + oper.opr.ref.refaddr:=addr_hi; + Consume(actasmtoken); + Consume(AS_LPAREN); + BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp); + if not assigned(oper.opr.ref.symbol) then + oper.opr.ref.symbol:=objectlibrary.newasmsymbol(tempstr,AB_EXTERNAL,tempsymtyp) + else + Message(asmr_e_cant_have_multiple_relocatable_symbols); + case oper.opr.typ of + OPR_CONSTANT : + inc(oper.opr.val,l); + OPR_LOCAL : + inc(oper.opr.localsymofs,l); + OPR_REFERENCE : + inc(oper.opr.ref.offset,l); + else + internalerror(200309202); + end; + Consume(AS_RPAREN); + gotplus:=false; + end; + + AS_ID: { A constant expression, or a Variable ref. } + Begin + { Local Label ? } + if is_locallabel(actasmpattern) then + begin + CreateLocalLabel(actasmpattern,hl,false); + Consume(AS_ID); + AddLabelOperand(hl); + end + else + { Check for label } + if SearchLabel(actasmpattern,hl,false) then + begin + Consume(AS_ID); + AddLabelOperand(hl); + end + else + { probably a variable or normal expression } + { or a procedure (such as in CALL ID) } + Begin + { is it a constant ? } + if SearchIConstant(actasmpattern,l) then + Begin + if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then + Message(asmr_e_invalid_operand_type); + BuildConstantOperand(oper); + end + else + begin + expr:=actasmpattern; + Consume(AS_ID); + { typecasting? } + if (actasmtoken=AS_LPAREN) and + SearchType(expr,typesize) then + begin + oper.hastype:=true; + Consume(AS_LPAREN); + BuildOperand(oper); + Consume(AS_RPAREN); + if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then + oper.SetSize(typesize,true); + end + else + begin + if oper.SetupVar(expr,false) then + ReadPercent(oper) + else + Begin + { look for special symbols ... } + if expr= '__HIGH' then + begin + consume(AS_LPAREN); + if not oper.setupvar('high'+actasmpattern,false) then + Message1(sym_e_unknown_id,'high'+actasmpattern); + consume(AS_ID); + consume(AS_RPAREN); + end + else + if expr = '__RESULT' then + oper.SetUpResult + else + if expr = '__SELF' then + oper.SetupSelf + else + if expr = '__OLDEBP' then + oper.SetupOldEBP + else + Message1(sym_e_unknown_id,expr); + end; + end; + end; + if actasmtoken=AS_DOT then + MaybeRecordOffset; + { add a constant expression? } + if (actasmtoken=AS_PLUS) then + begin + l:=BuildConstExpression(true,false); + case oper.opr.typ of + OPR_CONSTANT : + inc(oper.opr.val,l); + OPR_LOCAL : + inc(oper.opr.localsymofs,l); + OPR_REFERENCE : + inc(oper.opr.ref.offset,l); + else + internalerror(200309202); + end; + end + end; + gotplus:=false; + end; + + AS_REGISTER: { Register, a variable reference or a constant reference } + Begin + { save the type of register used. } + tempreg:=actasmregister; + Consume(AS_REGISTER); + if (oper.opr.typ in [OPR_REGISTER,OPR_REFERENCE]) and gotplus then + begin + oper.initref; + oper.opr.ref.refaddr:=addr_full; + if oper.opr.ref.base<>NR_NO then + oper.opr.ref.base:=tempreg + else + if oper.opr.ref.index<>NR_NO then + oper.opr.ref.index:=tempreg + else + Message(asmr_e_multiple_index); + end + else + begin + if (oper.opr.typ<>OPR_NONE) then + Message(asmr_e_invalid_operand_type); + oper.opr.typ:=OPR_REGISTER; + oper.opr.reg:=tempreg; + end; + gotplus:=false; + end; + + AS_END, + AS_SEPARATOR, + AS_COMMA: + break; + else + Begin + Message(asmr_e_syn_operand); + Consume(actasmtoken); + end; + end; { end case } + until false; + end; + + +{***************************************************************************** + TSparcReader +*****************************************************************************} + + procedure TSparcReader.BuildOpCode(instr : tSparcinstruction); + 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; + + { delayslot annulled? } + if (actasmtoken=AS_COMMA) then + begin + consume(AS_COMMA); + if actasmpattern='A' then + instr.delayslot_annulled:=true; + { force reading of AS_COMMA instead of AS_ID, otherwise + a label .L0 will first read a AS_DOT instead of AS_ID } + actasmtoken:=AS_COMMA; + consume(AS_COMMA); + 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 tSparcoperand); + end; { end case } + until false; + if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then + dec(operandnum); + instr.Ops:=operandnum; + end; + + + function TSparcReader.is_asmopcode(const s: string):boolean; + var + str2opEntry: tstr2opEntry; + cond:TAsmCond; + Begin + { making s a value parameter would break other assembler readers } + is_asmopcode:=false; + + { clear op code } + actopcode:=A_None; + { clear condition } + fillchar(actcondition,sizeof(actcondition),0); + + str2opentry:=tstr2opentry(iasmops.search(s)); + if assigned(str2opentry) then + begin + actopcode:=str2opentry.op; + actasmtoken:=AS_OPCODE; + is_asmopcode:=true; + end + { not found, check branch instructions } + else if (Upcase(s[1])='B') or + ((Upcase(s[1])='F') and (Upcase(s[2])='B')) then + begin + { we can search here without an extra table which is sorted by string length + because we take the whole remaining string without the leading B } + if (Upcase(s[1])='F') then + actopcode := A_FBxx + else + actopcode := A_Bxx; + for cond:=low(TAsmCond) to high(TAsmCond) do + if (Upper(copy(s,2,length(s)-1))=Upper(Cond2Str[cond])) then + begin + actasmtoken:=AS_OPCODE; + actcondition:=cond; + is_asmopcode:=true; + end; + end; + end; + + + procedure TSparcReader.ConvertCalljmp(instr : tSparcinstruction); + var + newopr : toprrec; + begin + if instr.Operands[1].opr.typ=OPR_REFERENCE then + with newopr do + begin + typ:=OPR_SYMBOL; + symbol:=instr.Operands[1].opr.ref.symbol; + symofs:=instr.Operands[1].opr.ref.offset; + if (instr.Operands[1].opr.ref.base<>NR_NO) or + (instr.Operands[1].opr.ref.index<>NR_NO) or + (instr.Operands[1].opr.ref.refaddr<>addr_full) then + Message(asmr_e_syn_operand); + instr.Operands[1].opr:=newopr; + end; + end; + + + procedure TSparcReader.handleopcode; + var + instr : tSparcinstruction; + begin + instr:=TSparcInstruction.Create(TSparcOperand); + BuildOpcode(instr); + with instr do + begin + condition := actcondition; + if is_calljmp(opcode) then + ConvertCalljmp(instr); + ConcatInstruction(curlist); + Free; + end; + end; + + +{***************************************************************************** + Initialize +*****************************************************************************} + +const + asmmode_Sparc_att_info : tasmmodeinfo = + ( + id : asmmode_Sparc_gas; + idtxt : 'GAS'; + casmreader : TSparcReader; + ); + + asmmode_Sparc_standard_info : tasmmodeinfo = + ( + id : asmmode_standard; + idtxt : 'STANDARD'; + casmreader : TSparcReader; + ); + +initialization + RegisterAsmMode(asmmode_Sparc_att_info); + RegisterAsmMode(asmmode_Sparc_standard_info); +end. diff --git a/compiler/sparc/rgcpu.pas b/compiler/sparc/rgcpu.pas new file mode 100644 index 0000000000..943158fffb --- /dev/null +++ b/compiler/sparc/rgcpu.pas @@ -0,0 +1,163 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + This unit implements the SPARC specific class for the register + allocator + + 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 rgcpu; + +{$i fpcdefs.inc} + + interface + + uses + aasmbase,aasmcpu,aasmtai, + cgbase,cgutils, + cpubase, + rgobj; + + type + trgcpu=class(trgobj) + procedure add_constraints(reg:tregister);override; + function get_spill_subreg(r : tregister) : tsubregister;override; + procedure do_spill_read(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);override; + procedure do_spill_written(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);override; + end; + + +implementation + + uses + verbose,cutils, + cgobj; + + procedure trgcpu.add_constraints(reg:tregister); + var + supreg,i : Tsuperregister; + begin + case getsubreg(reg) of + { Let 64bit floats conflict with all odd float regs } + R_SUBFD: + begin + supreg:=getsupreg(reg); + i:=RS_F1; + while (i<=RS_F31) do + begin + add_edge(supreg,i); + inc(i,2); + end; + end; + { Let 64bit ints conflict with all odd int regs } + R_SUBQ: + begin + supreg:=getsupreg(reg); + i:=RS_G1; + while (i<=RS_I7) do + begin + add_edge(supreg,i); + inc(i,2); + end; + end; + end; + end; + + + function trgcpu.get_spill_subreg(r : tregister) : tsubregister; + begin + if getregtype(r)=R_FPUREGISTER then + result:=getsubreg(r) + else + result:=defaultsub; + end; + + + procedure trgcpu.do_spill_read(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister); + var + helpins : tai; + tmpref : treference; + helplist : taasmoutput; + hreg : tregister; + begin + if abs(spilltemp.offset)>4095 then + begin + helplist:=taasmoutput.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=tempreg + else + hreg:=cg.getintregister(helplist,OS_ADDR); + + reference_reset(tmpref); + tmpref.offset:=spilltemp.offset; + tmpref.refaddr:=addr_hi; + helplist.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg)); + + tmpref.refaddr:=addr_lo; + helplist.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg)); + + reference_reset_base(tmpref,hreg,0); + tmpref.index:=spilltemp.base; + + helpins:=spilling_create_load(tmpref,tempreg); + helplist.concat(helpins); + list.insertlistafter(pos,helplist) + end + else + inherited do_spill_read(list,pos,spilltemp,tempreg); + end; + + + procedure trgcpu.do_spill_written(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister); + var + helpins : tai; + tmpref : treference; + helplist : taasmoutput; + hreg : tregister; + begin + if abs(spilltemp.offset)>4095 then + begin + helplist:=taasmoutput.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=getregisterinline(helplist,R_SUBWHOLE) + else + hreg:=cg.getintregister(helplist,OS_ADDR); + + reference_reset(tmpref); + tmpref.offset:=spilltemp.offset; + tmpref.refaddr:=addr_hi; + helplist.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg)); + + tmpref.refaddr:=addr_lo; + helplist.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg)); + + reference_reset_base(tmpref,hreg,0); + tmpref.index:=spilltemp.base; + + helpins:=spilling_create_store(tempreg,tmpref); + helplist.concat(helpins); + if getregtype(tempreg)=R_INTREGISTER then + ungetregisterinline(helplist,hreg); + + list.insertlistafter(pos,helplist) + end + else + inherited do_spill_written(list,pos,spilltemp,tempreg); + end; + +end. diff --git a/compiler/sparc/rspcon.inc b/compiler/sparc/rspcon.inc new file mode 100644 index 0000000000..5a84a0ba4e --- /dev/null +++ b/compiler/sparc/rspcon.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +NR_NO = tregister($00000000); +NR_G0 = tregister($01040000); +NR_G1 = tregister($01040001); +NR_G2 = tregister($01040002); +NR_G3 = tregister($01040003); +NR_G4 = tregister($01040004); +NR_G5 = tregister($01040005); +NR_G6 = tregister($01040006); +NR_G7 = tregister($01040007); +NR_O0 = tregister($01040008); +NR_O1 = tregister($01040009); +NR_O2 = tregister($0104000a); +NR_O3 = tregister($0104000b); +NR_O4 = tregister($0104000c); +NR_O5 = tregister($0104000d); +NR_O6 = tregister($0104000e); +NR_O7 = tregister($0104000f); +NR_L0 = tregister($01040010); +NR_L1 = tregister($01040011); +NR_L2 = tregister($01040012); +NR_L3 = tregister($01040013); +NR_L4 = tregister($01040014); +NR_L5 = tregister($01040015); +NR_L6 = tregister($01040016); +NR_L7 = tregister($01040017); +NR_I0 = tregister($01040018); +NR_I1 = tregister($01040019); +NR_I2 = tregister($0104001a); +NR_I3 = tregister($0104001b); +NR_I4 = tregister($0104001c); +NR_I5 = tregister($0104001d); +NR_I6 = tregister($0104001e); +NR_I7 = tregister($0104001f); +NR_FP = tregister($0104001e); +NR_SP = tregister($0104000e); +NR_F0 = tregister($02060000); +NR_F1 = tregister($02060001); +NR_F2 = tregister($02060002); +NR_F3 = tregister($02060003); +NR_F4 = tregister($02060004); +NR_F5 = tregister($02060005); +NR_F6 = tregister($02060006); +NR_F7 = tregister($02060007); +NR_F8 = tregister($02060008); +NR_F9 = tregister($02060009); +NR_F10 = tregister($0206000a); +NR_F11 = tregister($0206000b); +NR_F12 = tregister($0206000c); +NR_F13 = tregister($0206000d); +NR_F14 = tregister($0206000e); +NR_F15 = tregister($0206000f); +NR_F16 = tregister($02060010); +NR_F17 = tregister($02060011); +NR_F18 = tregister($02060012); +NR_F19 = tregister($02060013); +NR_F20 = tregister($02060014); +NR_F21 = tregister($02060015); +NR_F22 = tregister($02060016); +NR_F23 = tregister($02060017); +NR_F24 = tregister($02060018); +NR_F25 = tregister($02060019); +NR_F26 = tregister($0206001a); +NR_F27 = tregister($0206001b); +NR_F28 = tregister($0206001c); +NR_F29 = tregister($0206001d); +NR_F30 = tregister($0206001e); +NR_F31 = tregister($0206001f); +NR_C0 = tregister($03000000); +NR_C1 = tregister($03000001); +NR_C2 = tregister($03000002); +NR_C3 = tregister($03000003); +NR_C4 = tregister($03000004); +NR_C5 = tregister($03000005); +NR_C6 = tregister($03000006); +NR_C7 = tregister($03000007); +NR_C8 = tregister($03000008); +NR_C9 = tregister($03000009); +NR_C10 = tregister($0300000a); +NR_C11 = tregister($0300000b); +NR_C12 = tregister($0300000c); +NR_C13 = tregister($0300000d); +NR_C14 = tregister($0300000e); +NR_C15 = tregister($0300000f); +NR_C16 = tregister($03000010); +NR_C17 = tregister($03000011); +NR_C18 = tregister($03000012); +NR_C19 = tregister($03000013); +NR_C20 = tregister($03000014); +NR_C21 = tregister($03000015); +NR_C22 = tregister($03000016); +NR_C23 = tregister($03000017); +NR_C24 = tregister($03000018); +NR_C25 = tregister($03000019); +NR_C26 = tregister($0300001a); +NR_C27 = tregister($0300001b); +NR_C28 = tregister($0300001c); +NR_C29 = tregister($0300001d); +NR_C30 = tregister($0300001e); +NR_C31 = tregister($0300001f); +NR_FSR = tregister($05000000); +NR_FQ = tregister($05000001); +NR_CSR = tregister($05000002); +NR_CQ = tregister($05000003); +NR_PSR = tregister($05000004); +NR_TBR = tregister($05000005); +NR_WIM = tregister($05000006); +NR_Y = tregister($05000007); +NR_ASR0 = tregister($04000000); +NR_ASR1 = tregister($04000001); +NR_ASR2 = tregister($04000002); +NR_ASR3 = tregister($04000003); +NR_ASR4 = tregister($04000004); +NR_ASR5 = tregister($04000005); +NR_ASR6 = tregister($04000006); +NR_ASR7 = tregister($04000007); +NR_ASR8 = tregister($04000008); +NR_ASR9 = tregister($04000009); +NR_ASR10 = tregister($0400000a); +NR_ASR11 = tregister($0400000b); +NR_ASR12 = tregister($0400000c); +NR_ASR13 = tregister($0400000d); +NR_ASR14 = tregister($0400000e); +NR_ASR15 = tregister($0400000f); +NR_ASR16 = tregister($04000010); +NR_ASR17 = tregister($04000011); +NR_ASR18 = tregister($04000012); +NR_ASR19 = tregister($04000013); +NR_ASR20 = tregister($04000014); +NR_ASR21 = tregister($04000015); +NR_ASR22 = tregister($04000016); +NR_ASR23 = tregister($04000017); +NR_ASR24 = tregister($04000018); +NR_ASR25 = tregister($04000019); +NR_ASR26 = tregister($0400001a); +NR_ASR27 = tregister($0400001b); +NR_ASR28 = tregister($0400001c); +NR_ASR29 = tregister($0400001d); +NR_ASR30 = tregister($0400001e); +NR_ASR31 = tregister($0400001f); diff --git a/compiler/sparc/rspdwrf.inc b/compiler/sparc/rspdwrf.inc new file mode 100644 index 0000000000..b470be1e1d --- /dev/null +++ b/compiler/sparc/rspdwrf.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +-1, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +31, +15, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +64, +65, +64, +65, +64, +64, +64, +64, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32 diff --git a/compiler/sparc/rspnor.inc b/compiler/sparc/rspnor.inc new file mode 100644 index 0000000000..b6f96d936f --- /dev/null +++ b/compiler/sparc/rspnor.inc @@ -0,0 +1,2 @@ +{ don't edit, this file is generated from spreg.dat } +139 diff --git a/compiler/sparc/rspnum.inc b/compiler/sparc/rspnum.inc new file mode 100644 index 0000000000..b268537c8b --- /dev/null +++ b/compiler/sparc/rspnum.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +NR_NO, +NR_G0, +NR_G1, +NR_G2, +NR_G3, +NR_G4, +NR_G5, +NR_G6, +NR_G7, +NR_O0, +NR_O1, +NR_O2, +NR_O3, +NR_O4, +NR_O5, +NR_O6, +NR_O7, +NR_L0, +NR_L1, +NR_L2, +NR_L3, +NR_L4, +NR_L5, +NR_L6, +NR_L7, +NR_I0, +NR_I1, +NR_I2, +NR_I3, +NR_I4, +NR_I5, +NR_I6, +NR_I7, +NR_FP, +NR_SP, +NR_F0, +NR_F1, +NR_F2, +NR_F3, +NR_F4, +NR_F5, +NR_F6, +NR_F7, +NR_F8, +NR_F9, +NR_F10, +NR_F11, +NR_F12, +NR_F13, +NR_F14, +NR_F15, +NR_F16, +NR_F17, +NR_F18, +NR_F19, +NR_F20, +NR_F21, +NR_F22, +NR_F23, +NR_F24, +NR_F25, +NR_F26, +NR_F27, +NR_F28, +NR_F29, +NR_F30, +NR_F31, +NR_C0, +NR_C1, +NR_C2, +NR_C3, +NR_C4, +NR_C5, +NR_C6, +NR_C7, +NR_C8, +NR_C9, +NR_C10, +NR_C11, +NR_C12, +NR_C13, +NR_C14, +NR_C15, +NR_C16, +NR_C17, +NR_C18, +NR_C19, +NR_C20, +NR_C21, +NR_C22, +NR_C23, +NR_C24, +NR_C25, +NR_C26, +NR_C27, +NR_C28, +NR_C29, +NR_C30, +NR_C31, +NR_FSR, +NR_FQ, +NR_CSR, +NR_CQ, +NR_PSR, +NR_TBR, +NR_WIM, +NR_Y, +NR_ASR0, +NR_ASR1, +NR_ASR2, +NR_ASR3, +NR_ASR4, +NR_ASR5, +NR_ASR6, +NR_ASR7, +NR_ASR8, +NR_ASR9, +NR_ASR10, +NR_ASR11, +NR_ASR12, +NR_ASR13, +NR_ASR14, +NR_ASR15, +NR_ASR16, +NR_ASR17, +NR_ASR18, +NR_ASR19, +NR_ASR20, +NR_ASR21, +NR_ASR22, +NR_ASR23, +NR_ASR24, +NR_ASR25, +NR_ASR26, +NR_ASR27, +NR_ASR28, +NR_ASR29, +NR_ASR30, +NR_ASR31 diff --git a/compiler/sparc/rsprni.inc b/compiler/sparc/rsprni.inc new file mode 100644 index 0000000000..578709e2a8 --- /dev/null +++ b/compiler/sparc/rsprni.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +34, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +33, +32, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +99, +100, +101, +102, +103, +104, +105, +106 diff --git a/compiler/sparc/rspsri.inc b/compiler/sparc/rspsri.inc new file mode 100644 index 0000000000..da5ec0a078 --- /dev/null +++ b/compiler/sparc/rspsri.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +107, +108, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +109, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +110, +137, +138, +111, +112, +113, +114, +115, +116, +67, +68, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +69, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +70, +97, +98, +71, +72, +73, +74, +75, +76, +102, +101, +35, +36, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +37, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +38, +65, +66, +39, +40, +41, +42, +43, +44, +33, +100, +99, +1, +2, +3, +4, +5, +6, +7, +8, +25, +26, +27, +28, +29, +30, +31, +32, +17, +18, +19, +20, +21, +22, +23, +24, +9, +10, +11, +12, +13, +14, +15, +16, +103, +34, +104, +105, +106, +0 diff --git a/compiler/sparc/rspstab.inc b/compiler/sparc/rspstab.inc new file mode 100644 index 0000000000..b470be1e1d --- /dev/null +++ b/compiler/sparc/rspstab.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +-1, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +31, +15, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +64, +65, +64, +65, +64, +64, +64, +64, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32, +32 diff --git a/compiler/sparc/rspstd.inc b/compiler/sparc/rspstd.inc new file mode 100644 index 0000000000..189ed36a2f --- /dev/null +++ b/compiler/sparc/rspstd.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +'INVALID', +'%g0', +'%g1', +'%g2', +'%g3', +'%g4', +'%g5', +'%g6', +'%g7', +'%o0', +'%o1', +'%o2', +'%o3', +'%o4', +'%o5', +'%o6', +'%o7', +'%l0', +'%l1', +'%l2', +'%l3', +'%l4', +'%l5', +'%l6', +'%l7', +'%i0', +'%i1', +'%i2', +'%i3', +'%i4', +'%i5', +'%i6', +'%i7', +'%fp', +'%sp', +'%f0', +'%f1', +'%f2', +'%f3', +'%f4', +'%f5', +'%f6', +'%f7', +'%f8', +'%f9', +'%f10', +'%f11', +'%f12', +'%f13', +'%f14', +'%f15', +'%f16', +'%f17', +'%f18', +'%f19', +'%f20', +'%f21', +'%f22', +'%f23', +'%f24', +'%f25', +'%f26', +'%f27', +'%f28', +'%f29', +'%f30', +'%f31', +'%c0', +'%c1', +'%c2', +'%c3', +'%c4', +'%c5', +'%c6', +'%c7', +'%c8', +'%c9', +'%c10', +'%c11', +'%c12', +'%c13', +'%c14', +'%c15', +'%c16', +'%c17', +'%c18', +'%c19', +'%c20', +'%c21', +'%c22', +'%c23', +'%c24', +'%c25', +'%c26', +'%c27', +'%c28', +'%c29', +'%c30', +'%c31', +'%fsr', +'%fq', +'%csr', +'%cq', +'%psr', +'%tbr', +'%wim', +'%y', +'%asr0', +'%asr1', +'%asr2', +'%asr3', +'%asr4', +'%asr5', +'%asr6', +'%asr7', +'%asr8', +'%asr9', +'%asr10', +'%asr11', +'%asr12', +'%asr13', +'%asr14', +'%asr15', +'%asr16', +'%asr17', +'%asr18', +'%asr19', +'%asr20', +'%asr21', +'%asr22', +'%asr23', +'%asr24', +'%asr25', +'%asr26', +'%asr27', +'%asr28', +'%asr29', +'%asr30', +'%asr31' diff --git a/compiler/sparc/rspsup.inc b/compiler/sparc/rspsup.inc new file mode 100644 index 0000000000..68600f52a6 --- /dev/null +++ b/compiler/sparc/rspsup.inc @@ -0,0 +1,140 @@ +{ don't edit, this file is generated from spreg.dat } +RS_NO = $00; +RS_G0 = $00; +RS_G1 = $01; +RS_G2 = $02; +RS_G3 = $03; +RS_G4 = $04; +RS_G5 = $05; +RS_G6 = $06; +RS_G7 = $07; +RS_O0 = $08; +RS_O1 = $09; +RS_O2 = $0a; +RS_O3 = $0b; +RS_O4 = $0c; +RS_O5 = $0d; +RS_O6 = $0e; +RS_O7 = $0f; +RS_L0 = $10; +RS_L1 = $11; +RS_L2 = $12; +RS_L3 = $13; +RS_L4 = $14; +RS_L5 = $15; +RS_L6 = $16; +RS_L7 = $17; +RS_I0 = $18; +RS_I1 = $19; +RS_I2 = $1a; +RS_I3 = $1b; +RS_I4 = $1c; +RS_I5 = $1d; +RS_I6 = $1e; +RS_I7 = $1f; +RS_FP = $1e; +RS_SP = $0e; +RS_F0 = $00; +RS_F1 = $01; +RS_F2 = $02; +RS_F3 = $03; +RS_F4 = $04; +RS_F5 = $05; +RS_F6 = $06; +RS_F7 = $07; +RS_F8 = $08; +RS_F9 = $09; +RS_F10 = $0a; +RS_F11 = $0b; +RS_F12 = $0c; +RS_F13 = $0d; +RS_F14 = $0e; +RS_F15 = $0f; +RS_F16 = $10; +RS_F17 = $11; +RS_F18 = $12; +RS_F19 = $13; +RS_F20 = $14; +RS_F21 = $15; +RS_F22 = $16; +RS_F23 = $17; +RS_F24 = $18; +RS_F25 = $19; +RS_F26 = $1a; +RS_F27 = $1b; +RS_F28 = $1c; +RS_F29 = $1d; +RS_F30 = $1e; +RS_F31 = $1f; +RS_C0 = $00; +RS_C1 = $01; +RS_C2 = $02; +RS_C3 = $03; +RS_C4 = $04; +RS_C5 = $05; +RS_C6 = $06; +RS_C7 = $07; +RS_C8 = $08; +RS_C9 = $09; +RS_C10 = $0a; +RS_C11 = $0b; +RS_C12 = $0c; +RS_C13 = $0d; +RS_C14 = $0e; +RS_C15 = $0f; +RS_C16 = $10; +RS_C17 = $11; +RS_C18 = $12; +RS_C19 = $13; +RS_C20 = $14; +RS_C21 = $15; +RS_C22 = $16; +RS_C23 = $17; +RS_C24 = $18; +RS_C25 = $19; +RS_C26 = $1a; +RS_C27 = $1b; +RS_C28 = $1c; +RS_C29 = $1d; +RS_C30 = $1e; +RS_C31 = $1f; +RS_FSR = $00; +RS_FQ = $01; +RS_CSR = $02; +RS_CQ = $03; +RS_PSR = $04; +RS_TBR = $05; +RS_WIM = $06; +RS_Y = $07; +RS_ASR0 = $00; +RS_ASR1 = $01; +RS_ASR2 = $02; +RS_ASR3 = $03; +RS_ASR4 = $04; +RS_ASR5 = $05; +RS_ASR6 = $06; +RS_ASR7 = $07; +RS_ASR8 = $08; +RS_ASR9 = $09; +RS_ASR10 = $0a; +RS_ASR11 = $0b; +RS_ASR12 = $0c; +RS_ASR13 = $0d; +RS_ASR14 = $0e; +RS_ASR15 = $0f; +RS_ASR16 = $10; +RS_ASR17 = $11; +RS_ASR18 = $12; +RS_ASR19 = $13; +RS_ASR20 = $14; +RS_ASR21 = $15; +RS_ASR22 = $16; +RS_ASR23 = $17; +RS_ASR24 = $18; +RS_ASR25 = $19; +RS_ASR26 = $1a; +RS_ASR27 = $1b; +RS_ASR28 = $1c; +RS_ASR29 = $1d; +RS_ASR30 = $1e; +RS_ASR31 = $1f; diff --git a/compiler/sparc/spreg.dat b/compiler/sparc/spreg.dat new file mode 100644 index 0000000000..d254c4fc78 --- /dev/null +++ b/compiler/sparc/spreg.dat @@ -0,0 +1,154 @@ +; +; Sparc registers +; +; layout +; <name>,<regtype>,<regnum>,<stdname>,<stabidx>,<dwarfidx> +; +NO,$00,$00,$00,INVALID,-1,-1 +; Integer registers +G0,$01,$04,$00,%g0,1,1 +G1,$01,$04,$01,%g1,2,2 +G2,$01,$04,$02,%g2,3,3 +G3,$01,$04,$03,%g3,4,4 +G4,$01,$04,$04,%g4,5,5 +G5,$01,$04,$05,%g5,6,6 +G6,$01,$04,$06,%g6,7,7 +G7,$01,$04,$07,%g7,8,8 +O0,$01,$04,$08,%o0,9,9 +O1,$01,$04,$09,%o1,10,10 +O2,$01,$04,$0a,%o2,11,11 +O3,$01,$04,$0b,%o3,12,12 +O4,$01,$04,$0c,%o4,13,13 +O5,$01,$04,$0d,%o5,14,14 +O6,$01,$04,$0e,%o6,15,15 +O7,$01,$04,$0f,%o7,16,16 +L0,$01,$04,$10,%l0,17,17 +L1,$01,$04,$11,%l1,18,18 +L2,$01,$04,$12,%l2,19,19 +L3,$01,$04,$13,%l3,20,20 +L4,$01,$04,$14,%l4,21,21 +L5,$01,$04,$15,%l5,22,22 +L6,$01,$04,$16,%l6,23,23 +L7,$01,$04,$17,%l7,24,24 +I0,$01,$04,$18,%i0,25,25 +I1,$01,$04,$19,%i1,26,26 +I2,$01,$04,$1a,%i2,27,27 +I3,$01,$04,$1b,%i3,28,28 +I4,$01,$04,$1c,%i4,29,29 +I5,$01,$04,$1d,%i5,30,30 +I6,$01,$04,$1e,%i6,31,31 +I7,$01,$04,$1f,%i7,32,32 +; Aliases for stackpointer (%o6) and framepointer (%i6) +FP,$01,$04,$1e,%fp,31,31 +SP,$01,$04,$0e,%sp,15,15 +; Float registers, single use +F0,$02,$06,$00,%f0,32,32 +F1,$02,$06,$01,%f1,32,32 +F2,$02,$06,$02,%f2,32,32 +F3,$02,$06,$03,%f3,32,32 +F4,$02,$06,$04,%f4,32,32 +F5,$02,$06,$05,%f5,32,32 +F6,$02,$06,$06,%f6,32,32 +F7,$02,$06,$07,%f7,32,32 +F8,$02,$06,$08,%f8,32,32 +F9,$02,$06,$09,%f9,32,32 +F10,$02,$06,$0a,%f10,32,32 +F11,$02,$06,$0b,%f11,32,32 +F12,$02,$06,$0c,%f12,32,32 +F13,$02,$06,$0d,%f13,32,32 +F14,$02,$06,$0e,%f14,32,32 +F15,$02,$06,$0f,%f15,32,32 +F16,$02,$06,$10,%f16,32,32 +F17,$02,$06,$11,%f17,32,32 +F18,$02,$06,$12,%f18,32,32 +F19,$02,$06,$13,%f19,32,32 +F20,$02,$06,$14,%f20,32,32 +F21,$02,$06,$15,%f21,32,32 +F22,$02,$06,$16,%f22,32,32 +F23,$02,$06,$17,%f23,32,32 +F24,$02,$06,$18,%f24,32,32 +F25,$02,$06,$19,%f25,32,32 +F26,$02,$06,$1a,%f26,32,32 +F27,$02,$06,$1b,%f27,32,32 +F28,$02,$06,$1c,%f28,32,32 +F29,$02,$06,$1d,%f29,32,32 +F30,$02,$06,$1e,%f30,32,32 +F31,$02,$06,$1f,%f31,32,32 + +; Coprocessor registers +C0,$03,$00,$00,%c0,32,32 +C1,$03,$00,$01,%c1,32,32 +C2,$03,$00,$02,%c2,32,32 +C3,$03,$00,$03,%c3,32,32 +C4,$03,$00,$04,%c4,32,32 +C5,$03,$00,$05,%c5,32,32 +C6,$03,$00,$06,%c6,32,32 +C7,$03,$00,$07,%c7,32,32 +C8,$03,$00,$08,%c8,32,32 +C9,$03,$00,$09,%c9,32,32 +C10,$03,$00,$0a,%c10,32,32 +C11,$03,$00,$0b,%c11,32,32 +C12,$03,$00,$0c,%c12,32,32 +C13,$03,$00,$0d,%c13,32,32 +C14,$03,$00,$0e,%c14,32,32 +C15,$03,$00,$0f,%c15,32,32 +C16,$03,$00,$10,%c16,32,32 +C17,$03,$00,$11,%c17,32,32 +C18,$03,$00,$12,%c18,32,32 +C19,$03,$00,$13,%c19,32,32 +C20,$03,$00,$14,%c20,32,32 +C21,$03,$00,$15,%c21,32,32 +C22,$03,$00,$16,%c22,32,32 +C23,$03,$00,$17,%c23,32,32 +C24,$03,$00,$18,%c24,32,32 +C25,$03,$00,$19,%c25,32,32 +C26,$03,$00,$1a,%c26,32,32 +C27,$03,$00,$1b,%c27,32,32 +C28,$03,$00,$1c,%c28,32,32 +C29,$03,$00,$1d,%c29,32,32 +C30,$03,$00,$1e,%c30,32,32 +C31,$03,$00,$1f,%c31,32,32 + +; Special registers +FSR,$05,$00,$00,%fsr,64,64 +FQ,$05,$00,$01,%fq,65,65 +CSR,$05,$00,$02,%csr,64,64 +CQ,$05,$00,$03,%cq,65,65 +PSR,$05,$00,$04,%psr,64,64 +TBR,$05,$00,$05,%tbr,64,64 +WIM,$05,$00,$06,%wim,64,64 +Y,$05,$00,$07,%y,64,64 + +; Ancillary State Registers +ASR0,$04,$00,$00,%asr0,32,32 +ASR1,$04,$00,$01,%asr1,32,32 +ASR2,$04,$00,$02,%asr2,32,32 +ASR3,$04,$00,$03,%asr3,32,32 +ASR4,$04,$00,$04,%asr4,32,32 +ASR5,$04,$00,$05,%asr5,32,32 +ASR6,$04,$00,$06,%asr6,32,32 +ASR7,$04,$00,$07,%asr7,32,32 +ASR8,$04,$00,$08,%asr8,32,32 +ASR9,$04,$00,$09,%asr9,32,32 +ASR10,$04,$00,$0a,%asr10,32,32 +ASR11,$04,$00,$0b,%asr11,32,32 +ASR12,$04,$00,$0c,%asr12,32,32 +ASR13,$04,$00,$0d,%asr13,32,32 +ASR14,$04,$00,$0e,%asr14,32,32 +ASR15,$04,$00,$0f,%asr15,32,32 +ASR16,$04,$00,$10,%asr16,32,32 +ASR17,$04,$00,$11,%asr17,32,32 +ASR18,$04,$00,$12,%asr18,32,32 +ASR19,$04,$00,$13,%asr19,32,32 +ASR20,$04,$00,$14,%asr20,32,32 +ASR21,$04,$00,$15,%asr21,32,32 +ASR22,$04,$00,$16,%asr22,32,32 +ASR23,$04,$00,$17,%asr23,32,32 +ASR24,$04,$00,$18,%asr24,32,32 +ASR25,$04,$00,$19,%asr25,32,32 +ASR26,$04,$00,$1a,%asr26,32,32 +ASR27,$04,$00,$1b,%asr27,32,32 +ASR28,$04,$00,$1c,%asr28,32,32 +ASR29,$04,$00,$1d,%asr29,32,32 +ASR30,$04,$00,$1e,%asr30,32,32 +ASR31,$04,$00,$1f,%asr31,32,32 diff --git a/compiler/sparc/strinst.inc b/compiler/sparc/strinst.inc new file mode 100644 index 0000000000..e11b5c8d92 --- /dev/null +++ b/compiler/sparc/strinst.inc @@ -0,0 +1,69 @@ +{****************************************************************************** + *****************************************************************************} + 'none', + 'abcd', + 'add','addcc','addx','addxcc', + 'and','andcc','andn','andncc', + 'jmp', + 'jmpl', + 'call', + 'ba','b','fba','fb', + 'cbccc', + 'flush', + 'ldsb','ldsh','ldstub', + 'ldub','lduh','ld','ldd','ld','ldfsr','ldd','ldc','ldcsr','lddc', + 'ldsba','ldsha','lduba','lduha','lda','ldda', + 'ldstuba', + 'mulscc', + 'nop', + 'or','orcc','orn','orncc', + 'rd','rd','rd','rd','rd', + 'restore', + 'ret','retl', + 'save', + 'sdiv','sdivcc', + 'smul','smulcc', + 'sethi', + 'sll','srl','sra', + 'stb','sth','st','std','st','std','stfsr','stdfq', + 'stc','stdc','stcsr','stdcq', + 'stba','stha','sta','stda', + 'sub','subcc','subx','subxcc', + 'swap','swapa','ticc','taddcc','tsubcc','taddcctv','tsubcctv', + 'ta','t', + 'udiv','udivcc', + 'umul','umulcc', + 'unimp', + 'wrasr','wry','wrpsr','wrwim','wrtbr', + 'xnor','xnorcc', + 'xor','xorcc', + {floating-point instructions} + 'fitos','fitod','fitoq', + 'fstoi','fdtoi','fqtoi', + 'fstod','fstoq', + 'fdtos','fdtoq', + 'fqtod','fqtos', + 'fmovs','fnegs','fabss', + 'fsqrts','fsqrtd','fsqrtq', + 'fadds','faddd','faddq', + 'fsubs','fsubd','fsubq', + 'fmuls','fmuld','fmulq', + 'fdmulq','fsmuld', + 'fdivs','fdivd','fdivq', + 'fcmps','fcmpd','fcmpq', + 'fcpop1','cpop2', + {synthetic instructions} + 'btst','bset','bclr','btog', + 'clr','clrb','clrh', + 'cmp', + 'dec','deccc', + 'inc','inccc', + 'mov', + 'neg', + 'not', + 'set', + 'skipz','skipnz', + 'tst', + { internal instructions } + 'fmovd', + 'fabsd','fabsq' |