diff --git a/.gitattributes b/.gitattributes index 8b4b7086d9..fc320ef95e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -244,9 +244,15 @@ compiler/mips/cpuinfo.pas svneol=native#text/plain compiler/mips/cpunode.pas svneol=native#text/plain compiler/mips/cpupara.pas svneol=native#text/plain compiler/mips/cpupi.pas svneol=native#text/plain +compiler/mips/cputarg.pas svneol=native#text/pascal compiler/mips/itcpugas.pas svneol=native#text/plain compiler/mips/mipsreg.dat svneol=native#text/plain compiler/mips/ncpuadd.pas svneol=native#text/plain +compiler/mips/ncpucall.pas svneol=native#text/pascal +compiler/mips/ncpucnv.pas svneol=native#text/pascal +compiler/mips/ncpuinln.pas svneol=native#text/pascal +compiler/mips/ncpumat.pas svneol=native#text/pascal +compiler/mips/ncpuset.pas svneol=native#text/pascal compiler/mips/opcode.inc svneol=native#text/plain compiler/mips/rgcpu.pas svneol=native#text/plain compiler/mips/rmipscon.inc svneol=native#text/plain @@ -263,6 +269,7 @@ compiler/mips/rmipssri.inc svneol=native#text/plain compiler/mips/rmipssta.inc svneol=native#text/plain compiler/mips/rmipsstd.inc svneol=native#text/plain compiler/mips/rmipssup.inc svneol=native#text/plain +compiler/mips/strinst.inc svneol=native#text/plain compiler/msg/errorct.msg svneol=native#text/plain compiler/msg/errord.msg svneol=native#text/plain compiler/msg/errorda.msg svneol=native#text/plain diff --git a/compiler/arm/agarmgas.pas b/compiler/arm/agarmgas.pas index cecacaf30d..7f9fe88b3c 100644 --- a/compiler/arm/agarmgas.pas +++ b/compiler/arm/agarmgas.pas @@ -41,13 +41,13 @@ unit agarmgas; procedure WriteExtraHeader; override; end; - TArmInstrWriter=class(TCPUInstrWriter) + TArmInstrWriter=class(TCPUInstrWriter) procedure WriteInstruction(hp : tai);override; - end; + end; - TArmAppleGNUAssembler=class(TAppleGNUassembler) - constructor create(smart: boolean); override; - end; + TArmAppleGNUAssembler=class(TAppleGNUassembler) + constructor create(smart: boolean); override; + end; const @@ -95,7 +95,7 @@ unit agarmgas; end; {****************************************************************************} -{ GNU/Apple PPC Assembler writer } +{ GNU/Apple ARM Assembler writer } {****************************************************************************} constructor TArmAppleGNUAssembler.create(smart: boolean); diff --git a/compiler/mips/cpugas.pas b/compiler/mips/cpugas.pas index 23948471db..5a1fe5fd21 100644 --- a/compiler/mips/cpugas.pas +++ b/compiler/mips/cpugas.pas @@ -23,224 +23,243 @@ unit cpugas; {$i fpcdefs.inc} -interface + interface -uses - cpubase, - aasmtai, aasmcpu, assemble, aggas; + uses + cpubase, + aasmtai, aasmcpu, assemble, aggas; -type - TGasMIPSEL = 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 + ')'; + type + TMIPSGNUAssembler = class(TGNUassembler) + constructor create(smart: boolean); override; 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 + + TMIPSInstrWriter = class(TCPUInstrWriter) + procedure WriteInstruction(hp : tai);override; + end; + + implementation + + uses + cutils, systems, + verbose, itcpugas, cgbase, cgutils; + +{****************************************************************************} +{ GNU MIPS Assembler writer } +{****************************************************************************} + + constructor TMIPSGNUAssembler.create(smart: boolean); begin - if offset <> 0 then - GetReferenceString := ToStr(offset) + GetReferenceString; - if assigned(symbol) then + inherited create(smart); + InstrWriter := TMIPSInstrWriter.create(self); + end; + + +{****************************************************************************} +{ Helper routines for Instruction Writer } +{****************************************************************************} + + function GetReferenceString(var ref: TReference): string; + begin + GetReferenceString := ''; + with ref do begin - if refaddr = addr_lo then - GetReferenceString := '%lo(' + symbol.Name + ')' + GetReferenceString + 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_high: + GetReferenceString := '%hi(' + GetReferenceString + ')'; + addr_low: + GetReferenceString := '%lo(' + GetReferenceString + ')'; + end; + end else - GetReferenceString := symbol.Name + {'+' +} GetReferenceString; + 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 <> 0 then + GetReferenceString := ToStr(offset) + GetReferenceString; + if assigned(symbol) then + begin + if refaddr = addr_low 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 - 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; - -function getopstr_4(const Oper: TOper): string; -var - tmpref: treference; -begin - with Oper do - case typ of - top_ref: + function getopstr(const Oper: TOper): string; begin - tmpref := ref^; - Inc(tmpref.offset, 4); - getopstr_4 := getreferencestring(tmpref); + 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_low) 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; - else - internalerror(2007050403); - end; -end; - -procedure TGasMIPSEL.WriteInstruction(hp: Tai); -var - Op: TAsmOp; - s,s1: string; - i: integer; - tmpfpu: string; - tmpfpu_len: longint; -begin - if hp.typ <> ait_instruction then - exit; - op := taicpu(hp).opcode; - - case op of - A_P_STK2: - begin - s1 := getopstr(taicpu(hp).oper[2]^); - STK2_LocalSize := align(STK2_LocalSize, 8); - if s1[1] = '-' then - str(-STK2_LocalSize, s1) - else - str(STK2_LocalSize, s1); - s := #9 + std_op2str[A_ADDIU] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[1]^) + ',' + s1; - AsmWriteLn(s); - end; - A_P_FRAME: - begin - end; - A_P_SET_MACRO: - begin - s := #9 + '.set' + #9 + 'macro'; - AsmWriteLn(s); - end; - A_P_SET_REORDER: - begin - s := #9 + '.set' + #9 + 'reorder'; - AsmWriteLn(s); - end; - A_P_SET_NOMACRO: - begin - s := #9 + '.set' + #9 + 'nomacro'; - AsmWriteLn(s); - end; - A_P_SET_NOREORDER: - begin - s := #9 + '.set' + #9 + 'noreorder'; - AsmWriteLn(s); - end; - A_P_SW: - begin - s := #9 + std_op2str[A_SW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - end; - A_P_LW: - begin - s := #9 + std_op2str[A_LW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - end; - A_LDC1: - begin - tmpfpu := getopstr(taicpu(hp).oper[0]^); - s := #9 + std_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - - tmpfpu_len := length(tmpfpu); - tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]); - s := #9 + std_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - end; - A_SDC1: - begin - tmpfpu := getopstr(taicpu(hp).oper[0]^); - s := #9 + std_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - - tmpfpu_len := length(tmpfpu); - tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]); - s := #9 + std_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; - AsmWriteLn(s); - end; - else - begin - s := #9 + std_op2str[op] + cond2str[taicpu(hp).condition]; - if taicpu(hp).delayslot_annulled then - s := s + ',a'; - if taicpu(hp).ops > 0 then + function getopstr_4(const Oper: TOper): string; + var + tmpref: treference; 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]^); + with Oper do + case typ of + top_ref: + begin + tmpref := ref^; + Inc(tmpref.offset, 4); + getopstr_4 := getreferencestring(tmpref); + end; + else + internalerror(2007050403); + end; end; - AsmWriteLn(s); - end; - end; -end; -const - as_MIPSEL_as_info: tasminfo = - ( - id: as_gas; - idtxt: 'AS'; - asmbin: 'as'; - asmcmd: '-mips2 -W -EL -o $OBJ $ASM'; - supported_target: system_any; - flags: [af_allowdirect, af_needar, af_smartlink_sections]; - labelprefix: '.L'; - comment: '# '; - ); + procedure TMIPSInstrWriter.WriteInstruction(hp: Tai); + var + Op: TAsmOp; + s,s1: string; + i: integer; + tmpfpu: string; + tmpfpu_len: longint; + begin + if hp.typ <> ait_instruction then + exit; + op := taicpu(hp).opcode; + + case op of + A_P_STK2: + begin + s1 := getopstr(taicpu(hp).oper[2]^); + STK2_LocalSize := align(STK2_LocalSize, 8); + if s1[1] = '-' then + str(-STK2_LocalSize, s1) + else + str(STK2_LocalSize, s1); + s := #9 + gas_op2str[A_ADDIU] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[1]^) + ',' + s1; + owner.AsmWriteLn(s); + end; + A_P_FRAME: + begin + end; + A_P_SET_MACRO: + begin + s := #9 + '.set' + #9 + 'macro'; + owner.AsmWriteLn(s); + end; + A_P_SET_REORDER: + begin + s := #9 + '.set' + #9 + 'reorder'; + owner.AsmWriteLn(s); + end; + A_P_SET_NOMACRO: + begin + s := #9 + '.set' + #9 + 'nomacro'; + owner.AsmWriteLn(s); + end; + A_P_SET_NOREORDER: + begin + s := #9 + '.set' + #9 + 'noreorder'; + owner.AsmWriteLn(s); + end; + A_P_SW: + begin + s := #9 + gas_op2str[A_SW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + end; + A_P_LW: + begin + s := #9 + gas_op2str[A_LW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + end; + A_LDC1: + begin + tmpfpu := getopstr(taicpu(hp).oper[0]^); + s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + + tmpfpu_len := length(tmpfpu); + tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]); + s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + end; + A_SDC1: + begin + tmpfpu := getopstr(taicpu(hp).oper[0]^); + s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + + tmpfpu_len := length(tmpfpu); + tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]); + s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')'; + owner.AsmWriteLn(s); + end; + else + begin + s := #9 + gas_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; + owner.AsmWriteLn(s); + end; + end; + end; + + + const + as_MIPSEL_as_info: tasminfo = + ( + id: as_gas; + idtxt: 'AS'; + asmbin: 'as'; + asmcmd: '-mips2 -W -EL -o $OBJ $ASM'; + supported_targets: [system_mips_linux]; + flags: [af_allowdirect, af_needar, af_smartlink_sections]; + labelprefix: '.L'; + comment: '# '; + ); begin - RegisterAssembler(as_MIPSEL_as_info, TGasMIPSEL); + RegisterAssembler(as_MIPSEL_as_info, TMIPSGNUAssembler); end. diff --git a/compiler/mips/cputarg.pas b/compiler/mips/cputarg.pas new file mode 100644 index 0000000000..555935c6de --- /dev/null +++ b/compiler/mips/cputarg.pas @@ -0,0 +1,57 @@ +{ + 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 + + ; + +end. diff --git a/compiler/mips/itcpugas.pas b/compiler/mips/itcpugas.pas index c1fa15d809..d26b6497e4 100644 --- a/compiler/mips/itcpugas.pas +++ b/compiler/mips/itcpugas.pas @@ -1,5 +1,5 @@ { - Copyright (c) 1998-2005 by Florian Klaempfl + Copyright (c) 1998-2009 by Mazen NEIFER and David Zhang This unit contains the MIPS GAS instruction tables @@ -25,92 +25,77 @@ unit itcpugas; interface - uses - cpubase,cgbase; +uses + cpubase, cgbase; +const + gas_op2str: array[tasmop] of string[14] = ({$INCLUDE strinst.inc}); - const - { Standard opcode string table (for each tasmop enumeration). The - opcode strings should conform to the names as defined by the - processor manufacturer. - } - gas_op2str : op2strtable = ( - 'abs_d','abs_s','add','add_d','add_s','addi','addiu','addu', - 'and','andi','bc1f','bc1fl','bc1t','bc1tl','bc2f','bc2fl', - 'bc2t','bc2tl','beq','beql','bgez','bgezal','bgezall','bgezl', - 'bgtz','bgtzl','blez','blezl','bltz','bltzal','bltzall','bltzl', - 'bne','bnel','break','c_cond_d','c_cond_s','cache','ceil_w_d','ceil_w_s', - 'cfc1','cfc2','clo','clz','cop2','ctc1','ctc2','cvt_d_s', - 'cvt_d_w','cvt_s_d','cvt_s_w','cvt_w_d','cvt_w_s','div','div_d','div_s', - 'divu','eret','floor_w_d','floor_w_s','j','jal','jalr','jr', - 'lb','lbu','ldc1','ldc2','lh','lhu','ll','lui', - 'lw','lwc1','lwc2','lwl','lwr','madd','maddu','mfc0', - 'mfc1','mfc2','mfhi','mflo','mov_d','mov_s','movf','movf_d', - 'movf_s','movn','movn_d','movn_s','movt','movt_d','movt_s','movz', - 'movz_d','movz_s','msub','msubu','mtc0','mtc1','mtc2','mthi', - 'mtlo','mul','mul_d','mul_s','mult','multu','neg_d','neg_s', - 'nor','or','ori','pref','round_w_d','round_w_s','sb','sc', - 'sdc1','sdc2','sh','sll','sllv','slt','slti','sltiu', - 'sltu','sqrt_d','sqrt_s','sra','srav','srl','srlv','ssnop', - 'sub','sub_d','sub_s','subu','sw','swc1','swc2','swl', - 'swr','sync','syscall','teq','teqi','tge','tgei','tgeiu', - 'tgeu','tlbp','tlbr','tlbwi','tlbwr','tlt','tlti','tltiu', - 'tltu','tne','tnei','trunc_w_d','trunc_w_s','wait','xor','xori' - ); - - - function gas_regnum_search(const s:string):Tregister; - function gas_regname(r:Tregister):string; +function gas_regnum_search(const s: string): Tregister; +function gas_regname(r: Tregister): string; implementation - uses - cutils,verbose; +uses + cutils, verbose; - const - gas_regname_table : array[tregisterindex] of string[7] = ( - {$i rmipsgas.inc} - ); +const + gas_regname_table: array[tregisterindex] of string[7] = ( + {$i rmipsstd.inc} + ); - gas_regname_index : array[tregisterindex] of tregisterindex = ( + gas_regname_index: array[tregisterindex] of tregisterindex = ( {$i rmipssri.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 findreg_by_gasname(const s: string): tregisterindex; +var + i, p: tregisterindex; +begin + for p := low(tregisterindex) to high(tregisterindex) do + begin + if gas_regname_table[gas_regname_index[p]] = s then + begin + findreg_by_gasname := gas_regname_index[p]; + exit + end; + end; + findreg_by_gasname := 0; +end; - function gas_regname(r:Tregister):string; - var - p : tregisterindex; - begin - p:=findreg_by_number(r); - if p<>0 then - result:=gas_regname_table[p] - else - result:=generic_regname(r); - 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. +{ + $Log: itcpugas.pas,v $ + Revision 1.7 2005/02/14 17:13:10 peter + * truncate log + +} diff --git a/compiler/mips/ncpuadd.pas b/compiler/mips/ncpuadd.pas index 4a234ceebd..c8edb80acf 100644 --- a/compiler/mips/ncpuadd.pas +++ b/compiler/mips/ncpuadd.pas @@ -135,7 +135,7 @@ var lfcmp64_L4: tasmlabel; begin - objectlibrary.getlabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); @@ -155,7 +155,7 @@ var lfcmp64_L4: tasmlabel; begin - objectlibrary.getlabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L4); current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 1)); @@ -176,8 +176,8 @@ var begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); - objectlibrary.getlabel(lfcmp64_L4); - objectlibrary.getlabel(lfcmp64_L5); + current_asmdata.getjumplabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLT, NR_TCR11, left_reg.reghi, right_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); @@ -203,8 +203,8 @@ var begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); - objectlibrary.getlabel(lfcmp64_L4); - objectlibrary.getlabel(lfcmp64_L5); + current_asmdata.getjumplabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLT, NR_TCR11, right_reg.reghi, left_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); @@ -228,8 +228,8 @@ var begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); - objectlibrary.getlabel(lfcmp64_L4); - objectlibrary.getlabel(lfcmp64_L5); + current_asmdata.getjumplabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, left_reg.reghi, right_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L5)); @@ -255,8 +255,8 @@ var begin current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LI, NR_TCR10, 0)); - objectlibrary.getlabel(lfcmp64_L4); - objectlibrary.getlabel(lfcmp64_L5); + current_asmdata.getjumplabel(lfcmp64_L4); + current_asmdata.getjumplabel(lfcmp64_L5); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR11, right_reg.reghi, left_reg.reghi)); current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BNE, NR_TCR11, NR_R0, lfcmp64_L4)); @@ -422,7 +422,7 @@ begin op := A_C_EQ_D else op := A_C_EQ_S; - objectlibrary.getlabel(lfcmpfalse); + current_asmdata.getjumplabel(lfcmpfalse); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR, location.Register {NR_TCR0}, NR_R0, NR_R0)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1F, lfcmpfalse)); //lfcmpfalse @@ -437,7 +437,7 @@ begin op := A_C_EQ_D else op := A_C_EQ_S; - objectlibrary.getlabel(lfcmpfalse); + current_asmdata.getjumplabel(lfcmpfalse); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1F, lfcmpfalse)); @@ -451,7 +451,7 @@ begin op := A_C_LT_D else op := A_C_LT_S; - objectlibrary.getlabel(lfcmptrue); + current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); @@ -465,7 +465,7 @@ begin op := A_C_LE_D else op := A_C_LE_S; - objectlibrary.getlabel(lfcmptrue); + current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.Register, right.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); @@ -479,7 +479,7 @@ begin op := A_C_LT_D else op := A_C_LT_S; - objectlibrary.getlabel(lfcmptrue); + current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, right.location.Register, left.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); @@ -493,7 +493,7 @@ begin op := A_C_LE_D else op := A_C_LE_S; - objectlibrary.getlabel(lfcmptrue); + current_asmdata.getjumplabel(lfcmptrue); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ORI, location.Register{NR_TCR0}, NR_R0, 1)); current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, right.location.Register, left.location.Register)); current_asmdata.CurrAsmList.concat(Taicpu.op_sym(A_BC1T, lfcmptrue)); diff --git a/compiler/mips/ncpucall.pas b/compiler/mips/ncpucall.pas new file mode 100644 index 0000000000..65db4569c9 --- /dev/null +++ b/compiler/mips/ncpucall.pas @@ -0,0 +1,62 @@ +{ + Copyright (c) 1998-2009 by Florian Klaempfl and David Zhang + + Generate MIPSEL 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 + tMIPSELcallnode = class(tcgcallnode) + procedure extra_call_code; override; + procedure extra_post_call_code; override; + end; + + +implementation + +uses + cpubase, + aasmtai,aasmcpu,aasmdata, + paramgr, + ncal; + +procedure tMIPSELcallnode.extra_call_code; +begin + if pushedparasize > 0 then + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, -pushedparasize)); +end; + +procedure tMIPSELcallnode.extra_post_call_code; +begin + if pushedparasize > 0 then + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, pushedparasize)); + +end; + + +begin + ccallnode := TMIPSELCallNode; +end. diff --git a/compiler/mips/ncpucnv.pas b/compiler/mips/ncpucnv.pas new file mode 100644 index 0000000000..2a46d7c7fb --- /dev/null +++ b/compiler/mips/ncpucnv.pas @@ -0,0 +1,285 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl and David Zhang + + Generate MIPSEL 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 + tMIPSELtypeconvnode = 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, globtype, globals, systems, + symconst, symdef, aasmbase, aasmtai, aasmdata, + defutil, + cgbase, cgutils, pass_1, pass_2, procinfo, + ncon, ncal, + ncgutil, + cpubase, aasmcpu, + tgobj, cgobj; + + +{***************************************************************************** + FirstTypeConv +*****************************************************************************} + +function tMIPSELtypeconvnode.first_int_to_real: tnode; +var + fname: string[19]; +begin + { converting a 64bit integer to a float requires a helper } + if is_64bitint(left.resultdef) or + is_currency(left.resultdef) then + begin + { hack to avoid double division by 10000, as it's + already done by resulttypepass.resulttype_int_to_real } + if is_currency(left.resultdef) then + left.resultdef := s64inttype; + if is_signed(left.resultdef) 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.resultdef) then + inserttypeconv(left, s32inttype) + else + inserttypeconv(left, u32inttype); + firstpass(left); + end; + Result := nil; + expectloc := LOC_FPUREGISTER; +end; + + +{***************************************************************************** + SecondTypeConv +*****************************************************************************} + +procedure tMIPSELtypeconvnode.second_int_to_real; + + procedure loadsigned; + begin + location_force_mem(current_asmdata.CurrAsmList, left.location); + location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, location.size); + { Load memory in fpu register } + cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList, OS_F32, OS_F32, left.location.reference, location.Register); + tg.ungetiftemp(current_asmdata.CurrAsmList, left.location.reference); + { Convert value in fpu register from integer to float } + case tfloatdef(resultdef).floattype of + s32real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CVT_S_W, location.Register, location.Register)); + s64real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CVT_D_W, 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(resultdef)); + if is_signed(left.resultdef) then + loadsigned + else + begin + current_asmdata.getdatalabel(l1); + current_asmdata.getjumplabel(l2); + reference_reset_symbol(href, l1, 0, sizeof(aint)); + hregister := cg.getintregister(current_asmdata.CurrAsmList, OS_32); + cg.a_load_loc_reg(current_asmdata.CurrAsmList, OS_32, left.location, hregister); + + loadsigned; + + current_asmdata.CurrAsmList.concat(Taicpu.op_reg_reg_sym(A_BGE, hregister, NR_R0, l2)); + + case tfloatdef(resultdef).floattype of + { converting dword to s64real first and cut off at the end avoids precision loss } + s32real, + s64real: + begin + hregister := cg.getfpuregister(current_asmdata.CurrAsmList, OS_F64); + current_asmdata.asmlists[al_typedconsts].concat(tai_align.Create(const_align(8))); + current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l1)); + + { I got this constant from a test program (FK) } + current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_32bit(0)); + current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_32bit($0000f041)); + + cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList, OS_F64, OS_F64, href, hregister); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD_D, location.Register, hregister, location.Register)); + cg.a_label(current_asmdata.CurrAsmList, l2); + + { cut off if we should convert to single } + if tfloatdef(resultdef).floattype = s32real then + begin + hregister := location.Register; + location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, location.size); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CVT_S_D, location.Register, hregister)); + end; + end; + else + internalerror(200410031); + end; + end; +end; + + +procedure tMIPSELtypeconvnode.second_real_to_real; +const + conv_op: array[tfloattype, tfloattype] of tasmop = ( + { from: s32 s64 s80 c64 cur f128 } + { s32 } (A_MOV_S, A_CVT_S_D, A_NONE, A_NONE, A_NONE, A_NONE), + { s64 } (A_CVT_D_S, A_MOV_D, 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(resultdef)); + location_force_fpureg(current_asmdata.CurrAsmList, left.location, False); + { Convert value in fpu register from integer to float } + op := conv_op[tfloatdef(resultdef).floattype, tfloatdef(left.resultdef).floattype]; + if op = A_NONE then + internalerror(200401121); + location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, location.size); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, location.Register, left.location.Register)); +end; + + +procedure tMIPSELtypeconvnode.second_int_to_bool; +var + hreg1, hreg2: tregister; + opsize: tcgsize; + hlabel, oldtruelabel, oldfalselabel: tasmlabel; +begin + oldtruelabel := current_procinfo.CurrTrueLabel; + oldfalselabel := current_procinfo.CurrFalseLabel; + current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel); + current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel); + 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.resultdef.size = resultdef.size) and + (left.location.loc in [LOC_REFERENCE, LOC_CREFERENCE, LOC_CREGISTER]) then + begin + location_copy(location, left.location); + current_procinfo.CurrTrueLabel := oldtruelabel; + current_procinfo.CurrFalseLabel := oldfalselabel; + exit; + end; + location_reset(location, LOC_REGISTER, def_cgsize(resultdef)); + opsize := def_cgsize(left.resultdef); + 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(current_asmdata.CurrAsmList, opsize); + cg.a_load_ref_reg(current_asmdata.CurrAsmList, 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(current_asmdata.CurrAsmList, OS_32); + cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hreg2, tregister(succ(longint(hreg2))), hreg1); + hreg2 := hreg1; + opsize := OS_32; + end; +{$endif cpu64bit} + hreg1 := cg.getintregister(current_asmdata.CurrAsmList, opsize); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SNE, hreg1, hreg2, NR_R0)); + end; + LOC_JUMP: + begin + hreg1 := cg.getintregister(current_asmdata.CurrAsmList, OS_INT); + current_asmdata.getjumplabel(hlabel); + cg.a_label(current_asmdata.CurrAsmList, current_procinfo.CurrTrueLabel); + cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 1, hreg1); + cg.a_jmp_always(current_asmdata.CurrAsmList, hlabel); + cg.a_label(current_asmdata.CurrAsmList, current_procinfo.CurrFalseLabel); + cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, hreg1); + cg.a_label(current_asmdata.CurrAsmList, hlabel); + end; + else + internalerror(10062); + end; + location.Register := hreg1; + + if location.size in [OS_64, OS_S64] then + internalerror(200408241); + + current_procinfo.CurrTrueLabel := oldtruelabel; + current_procinfo.CurrFalseLabel := oldfalselabel; +end; + + +begin + ctypeconvnode := tMIPSELtypeconvnode; +end. diff --git a/compiler/mips/ncpuinln.pas b/compiler/mips/ncpuinln.pas new file mode 100644 index 0000000000..5470e9492e --- /dev/null +++ b/compiler/mips/ncpuinln.pas @@ -0,0 +1,138 @@ +{ + Copyright (c) 1998-2009 by Florian Klaempfl and David Zhang + + Generate MIPSEL 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 + tMIPSELinlinenode = 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, + globtype, + cutils, verbose, + symconst, symdef, + aasmtai, aasmcpu, aasmdata, + cgbase, pass_2, + cpubase, paramgr, + nbas, ncon, ncal, ncnv, nld, + ncgutil, cgobj, cgutils; + +{***************************************************************************** + tMIPSELinlinenode +*****************************************************************************} + +procedure tMIPSELinlinenode.load_fpu_location; +begin + secondpass(left); + location_force_fpureg(current_asmdata.CurrAsmList, left.location, True); + location_copy(location, left.location); + if left.location.loc = LOC_CFPUREGISTER then + begin + location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, location.size); + location.loc := LOC_FPUREGISTER; + end; +end; + + +function tMIPSELinlinenode.first_abs_real: tnode; +begin + expectloc := LOC_FPUREGISTER; + first_abs_real := nil; +end; + + +function tMIPSELinlinenode.first_sqr_real: tnode; +begin + expectloc := LOC_FPUREGISTER; + first_sqr_real := nil; +end; + + +function tMIPSELinlinenode.first_sqrt_real: tnode; +begin + expectloc := LOC_FPUREGISTER; + first_sqrt_real := nil; +end; + + +procedure tMIPSELinlinenode.second_abs_real; +begin + load_fpu_location; + case tfloatdef(left.resultdef).floattype of + s32real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_ABS_s, location.Register, left.location.Register)); + s64real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_ABS_d, location.Register, left.location.Register)); + else + internalerror(200410031); + end; +end; + + +procedure tMIPSELinlinenode.second_sqr_real; +begin + load_fpu_location; + case tfloatdef(left.resultdef).floattype of + s32real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MUL_s, location.Register, left.location.Register, left.location.Register)); + s64real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MUL_d, location.Register, left.location.Register, left.location.Register)); + else + internalerror(200410032); + end; +end; + + +procedure tMIPSELinlinenode.second_sqrt_real; +begin + load_fpu_location; + case tfloatdef(left.resultdef).floattype of + s32real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_SQRT_s, location.Register, left.location.Register)); + s64real: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_SQRT_d, location.Register, left.location.Register)); + else + internalerror(200410033); + end; +end; + +begin + cInlineNode := tMIPSELinlinenode; +end. diff --git a/compiler/mips/ncpumat.pas b/compiler/mips/ncpumat.pas new file mode 100644 index 0000000000..43d09598e8 --- /dev/null +++ b/compiler/mips/ncpumat.pas @@ -0,0 +1,302 @@ +{ +David Zhang 2007/01/15 + $Id: ncpumat.pas,v 1.23 2005/02/14 17:13:10 peter Exp $ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generate MIPSel 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 + tMIPSELmoddivnode = class(tmoddivnode) + procedure pass_generate_code;override; + end; + + tMIPSELshlshrnode = class(tshlshrnode) + procedure pass_generate_code;override; + { everything will be handled in pass_2 } + function first_shlshr64bitint: tnode; override; + end; + + tMIPSELnotnode = class(tcgnotnode) + procedure second_boolean; override; + end; + +implementation + +uses + globtype, systems, + cutils, verbose, globals, + symconst, + aasmbase, aasmcpu, aasmtai, aasmdata, + defutil, + procinfo, + cgbase, cgobj, pass_2, + ncon, + cpubase, + ncgutil, cgcpu, cgutils; + +{***************************************************************************** + TMipselMODDIVNODE +*****************************************************************************} + +procedure tMIPSELmoddivnode.pass_generate_code; +var + power: longint; + tmpreg, numerator, divider, resultreg: tregister; +begin + secondpass(left); + secondpass(right); + location_copy(location, left.location); + + { put numerator in register } + location_force_reg(current_asmdata.CurrAsmList, left.location, def_cgsize(left.resultdef), True); + location_copy(location, left.location); + numerator := location.Register; + + if (nodetype = modn) then + resultreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT) + else + begin + if (location.loc = LOC_CREGISTER) then + begin + location.loc := LOC_REGISTER; + location.Register := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); + end; + resultreg := location.Register; + end; + + if (nodetype = divn) and + (right.nodetype = ordconstn) and + ispowerof2(tordconstnode(right).Value.svalue, power) then + begin + tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, tmpreg); + { if signed, tmpreg=right value-1, otherwise 0 } + cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).Value.svalue - 1, tmpreg); + { add to the left value } + cg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_ADD, OS_INT, tmpreg, numerator); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, aword(power), numerator, resultreg); + end + else + begin + { load divider in a register if necessary } + location_force_reg(current_asmdata.CurrAsmList, right.location, + def_cgsize(right.resultdef), True); + divider := right.location.Register; + + + if (nodetype = modn) then + begin + if is_signed(right.resultdef) then + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_REM, resultreg, numerator, divider)); + end + else + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_REMU, resultreg, numerator, divider)); + end + else + begin + if is_signed({left.resultdef}right.resultdef) then + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_DIV, resultreg, numerator, divider)); + end + else + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_DIVU, resultreg, numerator, divider)); + end; + end; + { set result location } + location.loc := LOC_REGISTER; + location.Register := resultreg; +end; + + +{***************************************************************************** + TMIPSelSHLRSHRNODE +*****************************************************************************} + +function TMIPSELShlShrNode.first_shlshr64bitint: TNode; +begin + { 64bit without constants need a helper } + if is_64bit(left.resultdef) and + (right.nodetype <> ordconstn) then + begin + Result := inherited first_shlshr64bitint; + exit; + end; + + Result := nil; +end; + + +procedure tMIPSELshlshrnode.pass_generate_code; +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.resultdef) and + (right.nodetype <> ordconstn) then + internalerror(200405301); + + secondpass(left); + secondpass(right); + if is_64bit(left.resultdef) then + begin + location_reset(location, LOC_REGISTER, OS_64); + + { load left operator in a register } + location_force_reg(current_asmdata.CurrAsmList, left.location, OS_64, False); + + + hreg64hi := left.location.register64.reghi; + hreg64lo := left.location.register64.reglo; + + shiftval := tordconstnode(right).Value.svalue and 63; + if shiftval > 31 then + begin + if nodetype = shln then + begin + cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64hi); + if (shiftval and 31) <> 0 then + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval and 31, hreg64lo, hreg64lo); + end + else + begin + cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64lo); + if (shiftval and 31) <> 0 then + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval and 31, hreg64hi, hreg64hi); + end; + location.register64.reglo := hreg64hi; + location.register64.reghi := hreg64lo; + end + else + begin + hregister := cg.getintregister(current_asmdata.CurrAsmList, OS_32); + if nodetype = shln then + begin + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, 32 - shiftval, hreg64lo, hregister); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64hi, hreg64hi); + cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64hi, hreg64hi); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64lo, hreg64lo); + end + else + begin + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, 32 - shiftval, hreg64hi, hregister); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval, hreg64lo, hreg64lo); + cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64lo, hreg64lo); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, 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(current_asmdata.CurrAsmList, left.location, def_cgsize(left.resultdef), 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(current_asmdata.CurrAsmList, 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.svalue and 31 <> 0 then + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, op, OS_32, tordconstnode(right).Value.svalue and 31, hregister1, resultreg); + end + else + begin + { load shift count in a register if necessary } + location_force_reg(current_asmdata.CurrAsmList, right.location, def_cgsize(right.resultdef), True); + cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, op, OS_32, right.location.Register, hregister1, resultreg); + end; + end; +end; + + +{***************************************************************************** + TMIPSelNOTNODE +*****************************************************************************} + +procedure tMIPSELnotnode.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 := current_procinfo.CurrTrueLabel; + current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel; + current_procinfo.CurrFalseLabel := hl; + secondpass(left); + maketojumpbool(current_asmdata.CurrAsmList, left, lr_load_regvars); + hl := current_procinfo.CurrTrueLabel; + current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel; + current_procinfo.CurrFalseLabel := hl; + location.loc := LOC_JUMP; + end + else + begin + secondpass(left); + case left.location.loc of + LOC_FLAGS: + begin + internalerror(2007011501); + end; + LOC_REGISTER, LOC_CREGISTER, LOC_REFERENCE, LOC_CREFERENCE: + begin + location_force_reg(current_asmdata.CurrAsmList, left.location, def_cgsize(left.resultdef), True); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SEQ, NR_TCR0, left.location.Register, NR_R0)); + location_reset(location, LOC_REGISTER, OS_INT); + location.Register := NR_TCR0; + end; + else + internalerror(2003042401); + end; + end; +end; + + +begin + cmoddivnode := tMIPSELmoddivnode; + cshlshrnode := tMIPSELshlshrnode; + cnotnode := tMIPSELnotnode; +end. diff --git a/compiler/mips/ncpuset.pas b/compiler/mips/ncpuset.pas new file mode 100644 index 0000000000..ec311d1e05 --- /dev/null +++ b/compiler/mips/ncpuset.pas @@ -0,0 +1,130 @@ +{ + Copyright (c) 1998-2004 by Florian Klaempfl and David Zhang + + Generate MIPSEL 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, + constexp, + cpubase, + aasmbase, aasmtai, aasmcpu, aasmdata, + 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; + jumpsegment: TAsmlist; + + procedure genitem(t: pcaselabel); + var + i: aint; + begin + if assigned(t^.less) then + genitem(t^.less); + { fill possible hole } + for i := last.svalue+1 to t^._low.svalue-1 do + jumpSegment.concat(Tai_const.Create_sym(elselabel)); + for i := t^._low.svalue to t^._high.svalue do + jumpSegment.concat(Tai_const.Create_sym(blocklabel(t^.blockid))); + last := t^._high; + if assigned(t^.greater) then + genitem(t^.greater); + end; + +begin + jumpsegment := current_procinfo.aktlocaldata; + if not (jumptable_no_range) then + begin + { case expr less than min_ => goto elselabel } + cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList, opsize, jmp_lt, aint(min_), hregister, elselabel); + { case expr greater than max_ => goto elselabel } + cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList, opsize, jmp_gt, aint(max_), hregister, elselabel); + end; + current_asmdata.getjumplabel(table); + indexreg := cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_ADDR, 2, hregister, indexreg); + { create reference } + reference_reset_symbol(href, table, 0, sizeof(aint)); + href.offset := (-aint(min_)) * 4; + basereg := cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList, href, basereg); + + jmpreg := cg.getaddressregister(current_asmdata.CurrAsmList); + + reference_reset(href, sizeof(aint)); + href.index := indexreg; + href.base := basereg; + cg.a_load_ref_reg(current_asmdata.CurrAsmList, OS_ADDR, OS_ADDR, href, jmpreg); + + current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_JR, jmpreg)); + { Delay slot } + current_asmdata.CurrAsmList.concat(taicpu.op_none(A_NOP)); + { generate jump table } + if not(cs_opt_size in current_settings.optimizerswitches) then + jumpSegment.concat(Tai_Align.Create_Op(4, 0)); + jumpSegment.concat(Tai_label.Create(table)); + last := min_; + genitem(hp); +end; + + + +begin + ccasenode := tcpucasenode; +end. diff --git a/compiler/mips/strinst.inc b/compiler/mips/strinst.inc new file mode 100644 index 0000000000..10d6214ec0 --- /dev/null +++ b/compiler/mips/strinst.inc @@ -0,0 +1,241 @@ +'none', +'p_stk2', +'p_lw', +'p_set_noreorder', +'p_set_nomacro', +'p_set_macro', +'p_set_reorder', +'p_frame', +'p_mask', +'p_fmask', +'p_sw', +'sparc8unimp', +'nop', +'not', +'neg', +'negu', +'b', +'li', +'dli', +'la', +'move', +'lb', +'lbu', +'lh', +'lhu', +'lw', +'lwu', +'lwl', +'lwr', +'ld', +'ldl', +'ldr', +'ll', +'lld', +'sb', +'sh', +'sw', +'swl', +'swr', +'sd', +'sdl', +'sdr', +'sc', +'scd', +'sync', +'addi', +'daddi', +'addiu', +'daddiu', +'slti', +'sltiu', +'andi', +'ori', +'xori', +'lui', +'dneg', +'dnegu', +'add', +'dadd', +'addu', +'daddu', +'sub', +'dsub', +'subu', +'dsubu', +'slt', +'sltu', +'and', +'or', +'xor', +'nor', +'mul', +'mulo', +'mulou', +'dmul', +'dmulo', +'dmulou', +'div', +'divu', +'ddiv', +'ddivu', +'rem', +'remu', +'drem', +'dremu', +'mult', +'dmult', +'multu', +'dmultu', +'mfhi', +'mthi', +'mflo', +'mtlo', +'multg', +'dmultg', +'multug', +'dmultug', +'divg', +'ddivg', +'divug', +'ddivug', +'modg', +'dmodg', +'modug', +'dmodug', +'j', +'jal', +'jr', +'jalr', +'beq', +'bne', +'blez', +'bgtz', +'bltz', +'bgez', +'bltzal', +'bgezal', +'beql', +'bnel', +'blezl', +'bgtzl', +'bltzl', +'bgezl', +'bltzall', +'bgezall', +'sll', +'srl', +'sra', +'sllv', +'srlv', +'srav', +'dsll', +'dsrl', +'dsra', +'dsllv', +'dsrlv', +'dsrav', +'dsll32', +'dsrl32', +'dsra32', +'lwc1', +'swc1', +'ldc1', +'sdc1', +'mtc1', +'mfc1', +'dmtc1', +'dmfc1', +'ctc1', +'cfc1', +'add.s', +'add.d', +'sub.s', +'sub.d', +'mul.s', +'mul.d', +'div.s', +'div.d', +'abs.s', +'abs.d', +'neg.s', +'neg.d', +'sqrt.s', +'sqrt.d', +'mov.s', +'mov.d', +'cvt.s.d', +'cvt.s.w', +'cvt.s.l', +'cvt.d.s', +'cvt.d.w', +'cvt.d.l', +'cvt.w.s', +'cvt.w.d', +'cvt.l.s', +'cvt.l.d', +'round.w.s', +'round.w.d', +'round.l.s', +'round.l.d', +'trunc.w.s', +'trunc.w.d', +'trunc.l.s', +'trunc.l.d', +'ceil.w.s', +'ceil.w.d', +'ceil.l.s', +'ceil.l.d', +'floor.w.s', +'floor.w.d', +'floor.l.s', +'floor.l.d', +'bc1t', +'bc1f', +'bc1tl', +'bc1fl', +'c.eq.d', +'c.eq.s', +'c.le.d', +'c.le.s', +'c.lt.d', +'c.lt.s', +'beqi', +'bnei', +'blti', +'blei', +'bgti', +'bgei', +'bltui', +'bleui', +'bgtui', +'bgeui', +'blt', +'ble', +'bgt', +'bge', +'bltu', +'bleu', +'bgtu', +'bgeu', +'seq', +'sge', +'sgeu', +'sgt', +'sgtu', +'sle', +'sleu', +'sne', +'syscall', +'add64sub', +'sub64sub', +'mul64sub', +'div64sub', +'neg64sub', +'not64sub', +'or64sub', +'sar64sub', +'shl64sub', +'shr64sub', +'xor64sub', +'end_def' diff --git a/compiler/systems.pas b/compiler/systems.pas index 1565d80b12..7a535c619e 100644 --- a/compiler/systems.pas +++ b/compiler/systems.pas @@ -146,7 +146,8 @@ interface system_avr_embedded, { 62 } system_i386_haiku, { 63 } system_arm_darwin, { 64 } - system_x86_64_solaris { 65 } + system_x86_64_solaris, { 65 } + system_mips_linux { 66 } ); type diff --git a/compiler/systems/i_linux.pas b/compiler/systems/i_linux.pas index ec57c42d74..f486f42fe3 100644 --- a/compiler/systems/i_linux.pas +++ b/compiler/systems/i_linux.pas @@ -728,7 +728,69 @@ unit i_linux; ); {$endif FPC_ARMEB} {$endif FPC_ARMEL} - +{ + system_fvm32_linux_info : tsysteminfo = + ( + system : system_mips_LINUX; + name : 'Linux for MIPS'; + shortname : 'Linux'; + flags : [tf_needs_symbol_size]; + cpu : cpu_mips; + unit_env : 'LINUXUNITS'; + extradefines : 'UNIX;HASUNIX'; + exeext : ''; + defext : '.def'; + scriptext : '.sh'; + smartext : '.sl'; + unitext : '.ppu'; + unitlibext : '.ppl'; + asmext : '.s'; + objext : '.o'; + resext : '.res'; + resobjext : '.or'; + sharedlibext : '.so'; + staticlibext : '.a'; + staticlibprefix : 'libp'; + sharedlibprefix : 'lib'; + sharedClibext : '.so'; + staticClibext : '.a'; + staticClibprefix : 'lib'; + sharedClibprefix : 'lib'; +// p_ext_support : false; + Cprefix : ''; + newline : #10; + dirsep : '/'; + files_case_relevent : true; + assem : as_gas; + assemextern : as_gas; + link : nil; + linkextern : nil; + ar : ar_gnu_ar; + res : res_none; + script : script_unix; + endian : endian_little; + alignment : + ( + procalign : 4; + loopalign : 4; + jumpalign : 0; + constalignmin : 0; + constalignmax : 8; + varalignmin : 0; + varalignmax : 8; + localalignmin : 4; + localalignmax : 8; + recordalignmin : 0; + recordalignmax : 2; + maxCrecordalign : 4 + ); + first_parm_offset : 8; + stacksize : 32*1024*1024; + DllScanSupported:false; + use_function_relative_addresses : true; + abi : abi_default + ); +} implementation initialization @@ -775,5 +837,9 @@ initialization set_source_info(system_arm_linux_info); {$endif linux} {$endif CPUARM} +{$ifdef CPUMIPSEL} + {$ifdef linux} + set_source_info(system_mipsel_linux_info); + {$endif linux} +{$endif CPUMIPSEL} end. - diff --git a/compiler/systems/t_linux.pas b/compiler/systems/t_linux.pas index 8e80db5768..9598eeaaf7 100644 --- a/compiler/systems/t_linux.pas +++ b/compiler/systems/t_linux.pas @@ -137,6 +137,7 @@ const {$ifdef sparc} platform_select='-b elf32-sparc -m elf32_sparc';{$endif} {$ifdef arm} platform_select='';{$endif} {unknown :( } {$ifdef m68k} platform_select='';{$endif} {unknown :( } +{$ifdef mips} platform_select='';{$endif} {unknown :( } var defdynlinker: string; @@ -1163,5 +1164,11 @@ initialization RegisterExport(system_arm_linux,texportliblinux); RegisterTarget(system_arm_linux_info); {$endif ARM} +{$ifdef MIPS} + RegisterExternalLinker(system_mipsel_linux_info,TLinkerLinux); + RegisterImport(system_mipsel_linux,timportliblinux); + RegisterExport(system_mipsel_linux,texportliblinux); + RegisterTarget(system_mipsel_linux_info); +{$endif MIPS} RegisterRes(res_elf_info,TWinLikeResourceFile); end.