mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 10:39:26 +02:00
1178 lines
41 KiB
ObjectPascal
1178 lines
41 KiB
ObjectPascal
{
|
|
$Id$
|
|
|
|
Copyright (c) 2003 by Florian Klaempfl
|
|
Member of the Free Pascal development team
|
|
|
|
This unit implements the code generator for the ARM
|
|
|
|
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
|
|
symtype,
|
|
cgbase,cgobj,
|
|
aasmbase,aasmcpu,aasmtai,
|
|
cpubase,cpuinfo,node,cg64f32,cginfo;
|
|
|
|
|
|
type
|
|
tcgarm = class(tcg)
|
|
procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
|
|
procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
|
|
procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
|
|
|
|
procedure a_call_name(list : taasmoutput;const s : string);override;
|
|
procedure a_call_reg(list : taasmoutput;reg: tregister); override;
|
|
procedure a_call_ref(list : taasmoutput;const ref : treference);override;
|
|
|
|
procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; 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: aword; src, dst: tregister); override;
|
|
procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
|
|
size: tcgsize; src1, src2, dst: tregister); override;
|
|
|
|
{ move instructions }
|
|
procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);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;
|
|
|
|
{ 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 : aword;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_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
|
|
|
|
procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
|
|
|
|
procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);override;
|
|
procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
|
|
procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
|
|
procedure g_restore_frame_pointer(list : taasmoutput);override;
|
|
|
|
procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
|
|
|
|
procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
|
|
|
|
procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
|
|
|
|
procedure g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
|
|
procedure g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
|
|
procedure g_save_all_registers(list : taasmoutput);override;
|
|
procedure g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);override;
|
|
|
|
procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
|
|
procedure fixref(list : taasmoutput;var ref : treference);
|
|
procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
|
|
end;
|
|
|
|
tcg64farm = class(tcg64f32)
|
|
procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
|
|
procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
|
|
procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
|
|
procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
|
|
end;
|
|
|
|
const
|
|
OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
|
|
C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
|
|
|
|
function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
|
|
|
|
implementation
|
|
|
|
|
|
uses
|
|
globtype,globals,verbose,systems,cutils,symconst,symdef,symsym,rgobj,tgobj,cpupi;
|
|
|
|
|
|
procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
|
|
var
|
|
ref: treference;
|
|
begin
|
|
case locpara.loc of
|
|
LOC_REGISTER,LOC_CREGISTER:
|
|
a_load_const_reg(list,size,a,locpara.register);
|
|
LOC_REFERENCE:
|
|
begin
|
|
reference_reset(ref);
|
|
ref.base:=locpara.reference.index;
|
|
ref.offset:=locpara.reference.offset;
|
|
a_load_const_ref(list,size,a,ref);
|
|
end;
|
|
else
|
|
internalerror(2002081101);
|
|
end;
|
|
if locpara.sp_fixup<>0 then
|
|
internalerror(2002081102);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
|
|
var
|
|
ref: treference;
|
|
tmpreg: tregister;
|
|
begin
|
|
case locpara.loc of
|
|
LOC_REGISTER,LOC_CREGISTER:
|
|
a_load_ref_reg(list,size,size,r,locpara.register);
|
|
LOC_REFERENCE:
|
|
begin
|
|
reference_reset(ref);
|
|
ref.base:=locpara.reference.index;
|
|
ref.offset:=locpara.reference.offset;
|
|
tmpreg := rg.getregisterint(list,size);
|
|
a_load_ref_reg(list,size,size,r,tmpreg);
|
|
a_load_reg_ref(list,size,size,tmpreg,ref);
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
LOC_FPUREGISTER,LOC_CFPUREGISTER:
|
|
case size of
|
|
OS_F32, OS_F64:
|
|
a_loadfpu_ref_reg(list,size,r,locpara.register);
|
|
else
|
|
internalerror(2002072801);
|
|
end;
|
|
else
|
|
internalerror(2002081103);
|
|
end;
|
|
if locpara.sp_fixup<>0 then
|
|
internalerror(2002081104);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
|
|
var
|
|
ref: treference;
|
|
tmpreg: tregister;
|
|
begin
|
|
case locpara.loc of
|
|
LOC_REGISTER,LOC_CREGISTER:
|
|
a_loadaddr_ref_reg(list,r,locpara.register);
|
|
LOC_REFERENCE:
|
|
begin
|
|
reference_reset(ref);
|
|
ref.base := locpara.reference.index;
|
|
ref.offset := locpara.reference.offset;
|
|
tmpreg := rg.getregisterint(list,OS_ADDR);
|
|
a_loadaddr_ref_reg(list,r,tmpreg);
|
|
a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
else
|
|
internalerror(2002080701);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
|
|
begin
|
|
list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s)));
|
|
if not(pi_do_call in current_procinfo.flags) then
|
|
internalerror(2003060703);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
|
|
var
|
|
r : tregister;
|
|
begin
|
|
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
|
|
if not(pi_do_call in current_procinfo.flags) then
|
|
internalerror(2003060704);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_call_ref(list : taasmoutput;const ref : treference);
|
|
var
|
|
r : tregister;
|
|
begin
|
|
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_PC);
|
|
if not(pi_do_call in current_procinfo.flags) then
|
|
internalerror(2003060705);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
|
|
begin
|
|
a_op_const_reg_reg(list,op,size,a,reg,reg);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
|
|
begin
|
|
case op of
|
|
OP_NEG:
|
|
list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
|
|
OP_NOT:
|
|
list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
|
|
else
|
|
a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
|
|
end;
|
|
end;
|
|
|
|
|
|
const
|
|
op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
|
|
(A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
|
|
A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
|
|
|
|
|
|
procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
|
|
size: tcgsize; a: aword; src, dst: tregister);
|
|
var
|
|
shift : byte;
|
|
tmpreg : tregister;
|
|
so : tshifterop;
|
|
begin
|
|
if is_shifter_const(a,shift) and (not(op in [OP_IMUL,OP_MUL])) then
|
|
case op of
|
|
OP_NEG,OP_NOT,
|
|
OP_DIV,OP_IDIV:
|
|
internalerror(200308281);
|
|
OP_SHL:
|
|
begin
|
|
if a>32 then
|
|
internalerror(200308291);
|
|
shifterop_reset(so);
|
|
so.shiftmode:=SM_LSL;
|
|
so.shiftimm:=a;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
|
|
end;
|
|
OP_SHR:
|
|
begin
|
|
if a>32 then
|
|
internalerror(200308292);
|
|
shifterop_reset(so);
|
|
so.shiftmode:=SM_LSR;
|
|
so.shiftimm:=a;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
|
|
end;
|
|
OP_SAR:
|
|
begin
|
|
if a>32 then
|
|
internalerror(200308291);
|
|
shifterop_reset(so);
|
|
so.shiftmode:=SM_LSL;
|
|
so.shiftimm:=a;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
|
|
end;
|
|
else
|
|
list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
|
|
end
|
|
else
|
|
begin
|
|
{ there could be added some more sophisticated optimizations }
|
|
if (op in [OP_MUL,OP_IMUL]) and (a=1) then
|
|
a_load_reg_reg(list,size,size,src,dst)
|
|
else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
|
|
a_load_const_reg(list,size,0,dst)
|
|
else if (op in [OP_IMUL]) and (a=-1) then
|
|
a_op_reg_reg(list,OP_NEG,size,src,dst)
|
|
else
|
|
begin
|
|
tmpreg := rg.getregisterint(list,size);
|
|
a_load_const_reg(list,size,a,tmpreg);
|
|
a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
|
|
size: tcgsize; src1, src2, dst: tregister);
|
|
var
|
|
so : tshifterop;
|
|
tmpreg : tregister;
|
|
begin
|
|
case op of
|
|
OP_NEG,OP_NOT,
|
|
OP_DIV,OP_IDIV:
|
|
internalerror(200308281);
|
|
OP_SHL:
|
|
begin
|
|
shifterop_reset(so);
|
|
so.rs:=src1;
|
|
so.shiftmode:=SM_LSL;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
|
|
end;
|
|
OP_SHR:
|
|
begin
|
|
shifterop_reset(so);
|
|
so.rs:=src1;
|
|
so.shiftmode:=SM_LSR;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
|
|
end;
|
|
OP_SAR:
|
|
begin
|
|
shifterop_reset(so);
|
|
so.rs:=src1;
|
|
so.shiftmode:=SM_ASR;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
|
|
end;
|
|
OP_IMUL,
|
|
OP_MUL:
|
|
begin
|
|
{ the arm doesn't allow that rd and rm are the same }
|
|
if dst=src2 then
|
|
begin
|
|
if src1<>src2 then
|
|
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
|
|
else
|
|
begin
|
|
writeln('Warning: Fix MUL');
|
|
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
|
|
end;
|
|
end
|
|
else
|
|
list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
|
|
end;
|
|
else
|
|
list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
|
|
end;
|
|
end;
|
|
|
|
|
|
function rotl(d : dword;b : byte) : dword;
|
|
begin
|
|
result:=(d shr (32-b)) or (d shl b);
|
|
end;
|
|
|
|
|
|
function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
|
|
var
|
|
i : longint;
|
|
begin
|
|
for i:=0 to 15 do
|
|
begin
|
|
if (d and not(rotl($ff,i*2)))=0 then
|
|
begin
|
|
imm_shift:=i*2;
|
|
result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
|
|
var
|
|
imm_shift : byte;
|
|
l : tasmlabel;
|
|
hr : treference;
|
|
begin
|
|
if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
|
|
internalerror(2002090902);
|
|
if is_shifter_const(a,imm_shift) then
|
|
list.concat(taicpu.op_reg_const(A_MOV,reg,a))
|
|
else if is_shifter_const(not(a),imm_shift) then
|
|
list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
|
|
else
|
|
begin
|
|
objectlibrary.getdatalabel(l);
|
|
current_procinfo.aktlocaldata.concat(tai_symbol.Create(l,0));
|
|
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(a));
|
|
reference_reset(hr);
|
|
hr.symbol:=l;
|
|
list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
|
|
var
|
|
tmpreg : tregister;
|
|
tmpref : treference;
|
|
l : tasmlabel;
|
|
begin
|
|
tmpreg:=NR_NO;
|
|
|
|
{ Be sure to have a base register }
|
|
if (ref.base=NR_NO) then
|
|
begin
|
|
if ref.shiftmode<>SM_None then
|
|
internalerror(200308294);
|
|
ref.base:=ref.index;
|
|
ref.index:=NR_NO;
|
|
end;
|
|
|
|
{ absolute symbols can't be handled directly, we've to store the symbol reference
|
|
in the text segment and access it pc relative
|
|
|
|
For now, we assume that references where base or index equals to PC are already
|
|
relative, all other references are assumed to be absolute and thus they need
|
|
to be handled extra.
|
|
|
|
A proper solution would be to change refoptions to a set and store the information
|
|
if the symbol is absolute or relative there.
|
|
}
|
|
|
|
if (assigned(ref.symbol) and
|
|
not(is_pc(ref.base)) and
|
|
not(is_pc(ref.index))
|
|
) or
|
|
(ref.offset<-4095) or
|
|
(ref.offset>4095) or
|
|
((oppostfix in [PF_SB,PF_H,PF_SH]) and
|
|
((ref.offset<-255) or
|
|
(ref.offset>255)
|
|
)
|
|
) then
|
|
begin
|
|
{ check consts distance }
|
|
|
|
{ create consts entry }
|
|
objectlibrary.getdatalabel(l);
|
|
current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
|
|
if assigned(ref.symbol) then
|
|
current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
|
|
else
|
|
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
|
|
|
|
{ load consts entry }
|
|
tmpreg:=rg.getregisterint(list,OS_INT);
|
|
reference_reset(tmpref);
|
|
tmpref.symbol:=l;
|
|
tmpref.base:=NR_R15;
|
|
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
|
|
|
|
if (ref.base<>NR_NO) then
|
|
begin
|
|
if ref.index<>NR_NO then
|
|
begin
|
|
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
|
|
rg.ungetregister(list,ref.base);
|
|
ref.base:=tmpreg;
|
|
end
|
|
else
|
|
begin
|
|
ref.index:=tmpreg;
|
|
ref.shiftimm:=0;
|
|
ref.signindex:=1;
|
|
ref.shiftmode:=SM_None;
|
|
end;
|
|
end
|
|
else
|
|
ref.base:=tmpreg;
|
|
ref.offset:=0;
|
|
ref.symbol:=nil;
|
|
end;
|
|
list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
|
|
if (tmpreg<>NR_NO) then
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
|
|
var
|
|
oppostfix:toppostfix;
|
|
begin
|
|
case ToSize of
|
|
{ signed integer registers }
|
|
OS_8,
|
|
OS_S8:
|
|
oppostfix:=PF_B;
|
|
OS_16,
|
|
OS_S16:
|
|
oppostfix:=PF_H;
|
|
OS_32,
|
|
OS_S32:
|
|
oppostfix:=PF_None;
|
|
else
|
|
InternalError(200308295);
|
|
end;
|
|
handle_load_store(list,A_STR,oppostfix,reg,ref);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
|
|
var
|
|
oppostfix:toppostfix;
|
|
begin
|
|
case FromSize of
|
|
{ signed integer registers }
|
|
OS_8:
|
|
oppostfix:=PF_B;
|
|
OS_S8:
|
|
oppostfix:=PF_SB;
|
|
OS_16:
|
|
oppostfix:=PF_H;
|
|
OS_S16:
|
|
oppostfix:=PF_SH;
|
|
OS_32,
|
|
OS_S32:
|
|
oppostfix:=PF_None;
|
|
else
|
|
InternalError(200308291);
|
|
end;
|
|
handle_load_store(list,A_LDR,oppostfix,reg,ref);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
|
|
var
|
|
instr: taicpu;
|
|
so : tshifterop;
|
|
begin
|
|
shifterop_reset(so);
|
|
if (reg1<>reg2) or
|
|
(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:
|
|
instr := taicpu.op_reg_reg_const(A_AND,
|
|
reg2,reg1,$ff);
|
|
OS_S8:
|
|
begin
|
|
so.shiftmode:=SM_LSL;
|
|
so.shiftimm:=24;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
|
|
so.shiftmode:=SM_ASR;
|
|
so.shiftimm:=24;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
|
|
end;
|
|
OS_16:
|
|
begin
|
|
so.shiftmode:=SM_LSL;
|
|
so.shiftimm:=16;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
|
|
so.shiftmode:=SM_LSR;
|
|
so.shiftimm:=16;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
|
|
end;
|
|
OS_S16:
|
|
begin
|
|
so.shiftmode:=SM_LSL;
|
|
so.shiftimm:=16;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
|
|
so.shiftmode:=SM_ASR;
|
|
so.shiftimm:=16;
|
|
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
|
|
end;
|
|
OS_32,OS_S32:
|
|
begin
|
|
instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
|
|
rg.add_move_instruction(instr);
|
|
list.concat(instr);
|
|
end;
|
|
else internalerror(2002090901);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
|
|
begin
|
|
list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
|
|
var
|
|
oppostfix:toppostfix;
|
|
begin
|
|
case size of
|
|
OS_F32:
|
|
oppostfix:=PF_S;
|
|
OS_F64:
|
|
oppostfix:=PF_D;
|
|
OS_F80:
|
|
oppostfix:=PF_E;
|
|
else
|
|
InternalError(200309021);
|
|
end;
|
|
handle_load_store(list,A_LDF,oppostfix,reg,ref);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
|
|
var
|
|
oppostfix:toppostfix;
|
|
begin
|
|
case size of
|
|
OS_F32:
|
|
oppostfix:=PF_S;
|
|
OS_F64:
|
|
oppostfix:=PF_D;
|
|
OS_F80:
|
|
oppostfix:=PF_E;
|
|
else
|
|
InternalError(200309021);
|
|
end;
|
|
handle_load_store(list,A_STF,oppostfix,reg,ref);
|
|
end;
|
|
|
|
|
|
{ comparison operations }
|
|
procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
|
|
l : tasmlabel);
|
|
var
|
|
tmpreg : tregister;
|
|
b : byte;
|
|
begin
|
|
if is_shifter_const(a,b) then
|
|
list.concat(taicpu.op_reg_const(A_CMN,reg,a))
|
|
{ CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
|
|
and CMP reg,$7fffffff regarding the flags according to the ARM manual }
|
|
else if is_shifter_const(not(a),b) and (a<>$7fffffff) and (a<>$ffffffff) then
|
|
list.concat(taicpu.op_reg_const(A_CMN,reg,not(a)))
|
|
else
|
|
begin
|
|
tmpreg:=rg.getregisterint(list,size);
|
|
a_load_const_reg(list,size,a,tmpreg);
|
|
list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
a_jmp_cond(list,cmp_op,l);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
|
|
begin
|
|
list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
|
|
a_jmp_cond(list,cmp_op,l);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
|
|
begin
|
|
list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name)));
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
|
|
var
|
|
ai : taicpu;
|
|
begin
|
|
ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
|
|
ai.is_jmp:=true;
|
|
list.concat(ai);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
|
|
var
|
|
ai : taicpu;
|
|
begin
|
|
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
|
|
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
|
|
var
|
|
ref : treference;
|
|
begin
|
|
LocalSize:=align(LocalSize,4);
|
|
|
|
a_reg_alloc(list,NR_STACK_POINTER_REG);
|
|
a_reg_alloc(list,NR_FRAME_POINTER_REG);
|
|
a_reg_alloc(list,NR_R12);
|
|
|
|
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
|
|
{ save int registers }
|
|
reference_reset(ref);
|
|
ref.index:=NR_STACK_POINTER_REG;
|
|
ref.addressmode:=AM_PREINDEXED;
|
|
list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R12,RS_R15]),PF_FD));
|
|
|
|
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
|
|
a_reg_alloc(list,NR_R12);
|
|
|
|
{ allocate necessary stack size }
|
|
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
|
|
var
|
|
ref : treference;
|
|
begin
|
|
if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
|
|
list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
|
|
else
|
|
begin
|
|
{ restore int registers and return }
|
|
reference_reset(ref);
|
|
ref.index:=NR_FRAME_POINTER_REG;
|
|
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R13,RS_R15]),PF_EA));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
|
|
begin
|
|
{ the frame pointer on the ARM is restored while the ret is executed }
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
|
|
var
|
|
b : byte;
|
|
tmpref : treference;
|
|
instr : taicpu;
|
|
begin
|
|
if ref.addressmode<>AM_OFFSET then
|
|
internalerror(200309071);
|
|
tmpref:=ref;
|
|
{ Be sure to have a base register }
|
|
if (tmpref.base=NR_NO) then
|
|
begin
|
|
if tmpref.shiftmode<>SM_None then
|
|
internalerror(200308294);
|
|
tmpref.base:=tmpref.index;
|
|
tmpref.index:=NR_NO;
|
|
end;
|
|
|
|
if assigned(tmpref.symbol) or
|
|
not(is_shifter_const(tmpref.offset,b)) or
|
|
((tmpref.base<>NR_NO) and (tmpref.index<>NR_NO)) then
|
|
fixref(list,tmpref);
|
|
|
|
if tmpref.index<>NR_NO then
|
|
begin
|
|
{!!!!!!!}
|
|
end
|
|
else
|
|
begin
|
|
if tmpref.offset>0 then
|
|
list.concat(taicpu.op_reg_reg_const(A_ADD,r,tmpref.base,tmpref.offset))
|
|
else if tmpref.offset<0 then
|
|
list.concat(taicpu.op_reg_reg_const(A_SUB,r,tmpref.base,-tmpref.offset))
|
|
else
|
|
begin
|
|
instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
|
|
rg.add_move_instruction(instr);
|
|
list.concat(instr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
|
|
var
|
|
tmpreg : tregister;
|
|
tmpref : treference;
|
|
l : tasmlabel;
|
|
begin
|
|
{ absolute symbols can't be handled directly, we've to store the symbol reference
|
|
in the text segment and access it pc relative
|
|
|
|
For now, we assume that references where base or index equals to PC are already
|
|
relative, all other references are assumed to be absolute and thus they need
|
|
to be handled extra.
|
|
|
|
A proper solution would be to change refoptions to a set and store the information
|
|
if the symbol is absolute or relative there.
|
|
}
|
|
|
|
{ check consts distance }
|
|
{!!!!!}
|
|
|
|
{ create consts entry }
|
|
objectlibrary.getdatalabel(l);
|
|
current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
|
|
if assigned(ref.symbol) then
|
|
current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
|
|
else
|
|
current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
|
|
|
|
{ load consts entry }
|
|
tmpreg:=rg.getregisterint(list,OS_INT);
|
|
reference_reset(tmpref);
|
|
tmpref.symbol:=l;
|
|
tmpref.base:=NR_PC;
|
|
list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
|
|
|
|
if (ref.base<>NR_NO) then
|
|
begin
|
|
if ref.index<>NR_NO then
|
|
begin
|
|
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
|
|
rg.ungetregisterint(list,ref.base);
|
|
ref.base:=tmpreg;
|
|
end
|
|
else
|
|
begin
|
|
ref.index:=tmpreg;
|
|
ref.shiftimm:=0;
|
|
ref.signindex:=1;
|
|
ref.shiftmode:=SM_None;
|
|
end;
|
|
end
|
|
else
|
|
ref.base:=tmpreg;
|
|
ref.offset:=0;
|
|
ref.symbol:=nil;
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
|
|
var
|
|
srcref,dstref:treference;
|
|
srcreg,destreg,countreg,r:tregister;
|
|
helpsize:aword;
|
|
copysize:byte;
|
|
cgsize:Tcgsize;
|
|
|
|
procedure genloop(count : aword;size : byte);
|
|
const
|
|
size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
|
|
var
|
|
l : tasmlabel;
|
|
begin
|
|
objectlibrary.getdatalabel(l);
|
|
a_load_const_reg(list,OS_INT,count,countreg);
|
|
list.concat(Tai_symbol.Create(l,0));
|
|
srcref.addressmode:=AM_POSTINDEXED;
|
|
dstref.addressmode:=AM_POSTINDEXED;
|
|
srcref.offset:=size;
|
|
dstref.offset:=size;
|
|
r:=rg.getregisterint(list,size2opsize[size]);
|
|
a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
|
|
a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
|
|
rg.ungetregisterint(list,r);
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
|
|
list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
|
|
end;
|
|
|
|
begin
|
|
helpsize:=12;
|
|
dstref:=dest;
|
|
srcref:=source;
|
|
if cs_littlesize in aktglobalswitches then
|
|
helpsize:=8;
|
|
if not loadref and (len<=helpsize) then
|
|
begin
|
|
copysize:=4;
|
|
cgsize:=OS_32;
|
|
while len<>0 do
|
|
begin
|
|
if len<2 then
|
|
begin
|
|
copysize:=1;
|
|
cgsize:=OS_8;
|
|
end
|
|
else if len<4 then
|
|
begin
|
|
copysize:=2;
|
|
cgsize:=OS_16;
|
|
end;
|
|
dec(len,copysize);
|
|
r:=rg.getregisterint(list,cgsize);
|
|
a_load_ref_reg(list,cgsize,cgsize,srcref,r);
|
|
if (len=0) and delsource then
|
|
reference_release(list,source);
|
|
a_load_reg_ref(list,cgsize,cgsize,r,dstref);
|
|
inc(srcref.offset,copysize);
|
|
inc(dstref.offset,copysize);
|
|
rg.ungetregisterint(list,r);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
destreg:=rg.getregisterint(list,OS_ADDR);
|
|
a_loadaddr_ref_reg(list,dest,destreg);
|
|
srcreg:=rg.getregisterint(list,OS_ADDR);
|
|
if loadref then
|
|
a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
|
|
else
|
|
begin
|
|
a_loadaddr_ref_reg(list,source,srcreg);
|
|
if delsource then
|
|
begin
|
|
srcref:=source;
|
|
reference_release(list,srcref);
|
|
end;
|
|
end;
|
|
|
|
countreg:=rg.getregisterint(list,OS_32);
|
|
|
|
// if cs_littlesize in aktglobalswitches then
|
|
genloop(len,1);
|
|
{
|
|
else
|
|
begin
|
|
helpsize:=len shr 2;
|
|
len:=len and 3;
|
|
if helpsize>1 then
|
|
begin
|
|
a_load_const_reg(list,OS_INT,helpsize,countreg);
|
|
list.concat(Taicpu.op_none(A_REP,S_NO));
|
|
end;
|
|
if helpsize>0 then
|
|
list.concat(Taicpu.op_none(A_MOVSD,S_NO));
|
|
if len>1 then
|
|
begin
|
|
dec(len,2);
|
|
list.concat(Taicpu.op_none(A_MOVSW,S_NO));
|
|
end;
|
|
if len=1 then
|
|
list.concat(Taicpu.op_none(A_MOVSB,S_NO));
|
|
end;
|
|
}
|
|
rg.ungetregisterint(list,countreg);
|
|
rg.ungetregisterint(list,srcreg);
|
|
rg.ungetregisterint(list,destreg);
|
|
end;
|
|
if delsource then
|
|
tg.ungetiftemp(list,source);
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
|
|
begin
|
|
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
|
|
begin
|
|
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_save_all_registers(list : taasmoutput);
|
|
begin
|
|
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
|
|
end;
|
|
|
|
|
|
procedure tcgarm.g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);
|
|
begin
|
|
{ we support only ARM standard calling conventions so this procedure has no use on the ARM }
|
|
end;
|
|
|
|
|
|
procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
|
|
var
|
|
ai : taicpu;
|
|
begin
|
|
ai:=Taicpu.Op_sym(A_B,l);
|
|
ai.SetCondition(OpCmp2AsmCond[cond]);
|
|
ai.is_jmp:=true;
|
|
list.concat(ai);
|
|
end;
|
|
|
|
|
|
procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
|
|
var
|
|
tmpreg : tregister;
|
|
begin
|
|
case op of
|
|
OP_NEG:
|
|
begin
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
|
|
list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
|
|
end;
|
|
else
|
|
a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
|
|
begin
|
|
a_op64_const_reg_reg(list,op,value,reg,reg);
|
|
end;
|
|
|
|
|
|
procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
|
|
var
|
|
tmpreg : tregister;
|
|
b : byte;
|
|
begin
|
|
case op of
|
|
OP_AND,OP_OR,OP_XOR:
|
|
begin
|
|
cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
|
|
cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
|
|
end;
|
|
OP_ADD:
|
|
begin
|
|
if is_shifter_const(lo(value),b) then
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
|
|
else
|
|
begin
|
|
tmpreg:=rg.getregisterint(list,OS_32);
|
|
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
|
|
if is_shifter_const(hi(value),b) then
|
|
list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
|
|
else
|
|
begin
|
|
tmpreg:=rg.getregisterint(list,OS_32);
|
|
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
|
|
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
end;
|
|
OP_SUB:
|
|
begin
|
|
if is_shifter_const(lo(value),b) then
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
|
|
else
|
|
begin
|
|
tmpreg:=rg.getregisterint(list,OS_32);
|
|
cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
|
|
if is_shifter_const(hi(value),b) then
|
|
list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
|
|
else
|
|
begin
|
|
tmpreg:=rg.getregisterint(list,OS_32);
|
|
cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
|
|
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
|
|
rg.ungetregisterint(list,tmpreg);
|
|
end;
|
|
end;
|
|
else
|
|
internalerror(2003083101);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
|
|
begin
|
|
case op of
|
|
OP_AND,OP_OR,OP_XOR:
|
|
begin
|
|
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
|
|
cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
|
|
end;
|
|
OP_ADD:
|
|
begin
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
|
|
list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
|
|
end;
|
|
OP_SUB:
|
|
begin
|
|
list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
|
|
list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
|
|
end;
|
|
else
|
|
internalerror(2003083101);
|
|
end;
|
|
end;
|
|
|
|
|
|
begin
|
|
cg:=tcgarm.create;
|
|
cg64:=tcg64farm.create;
|
|
end.
|
|
{
|
|
$Log$
|
|
Revision 1.18 2003-09-09 12:53:40 florian
|
|
* some assembling problems fixed
|
|
* improved loadaddr_ref_reg
|
|
|
|
Revision 1.17 2003/09/06 16:45:51 florian
|
|
* fixed exit code (no preindexed addressing mode in LDM)
|
|
|
|
Revision 1.16 2003/09/06 11:21:50 florian
|
|
* fixed stm and ldm to be usable with preindex operand
|
|
|
|
Revision 1.15 2003/09/05 23:57:01 florian
|
|
* arm is working again as before the new register naming scheme was implemented
|
|
|
|
Revision 1.14 2003/09/04 21:07:03 florian
|
|
* ARM compiler compiles again
|
|
|
|
Revision 1.13 2003/09/04 00:15:29 florian
|
|
* first bunch of adaptions of arm compiler for new register type
|
|
|
|
Revision 1.12 2003/09/03 19:10:30 florian
|
|
* initial revision of new register naming
|
|
|
|
Revision 1.11 2003/09/03 11:18:37 florian
|
|
* fixed arm concatcopy
|
|
+ arm support in the common compiler sources added
|
|
* moved some generic cg code around
|
|
+ tfputype added
|
|
* ...
|
|
|
|
Revision 1.10 2003/09/01 15:11:16 florian
|
|
* fixed reference handling
|
|
* fixed operand postfix for floating point instructions
|
|
* fixed wrong shifter constant handling
|
|
|
|
Revision 1.9 2003/09/01 09:54:57 florian
|
|
* results of work on arm port last weekend
|
|
|
|
Revision 1.8 2003/08/29 21:36:28 florian
|
|
* fixed procedure entry/exit code
|
|
* started to fix reference handling
|
|
|
|
Revision 1.7 2003/08/28 13:26:10 florian
|
|
* another couple of arm fixes
|
|
|
|
Revision 1.6 2003/08/28 00:05:29 florian
|
|
* today's arm patches
|
|
|
|
Revision 1.5 2003/08/25 23:20:38 florian
|
|
+ started to implement FPU support for the ARM
|
|
* fixed a lot of other things
|
|
|
|
Revision 1.4 2003/08/24 12:27:26 florian
|
|
* continued to work on the arm port
|
|
|
|
Revision 1.3 2003/08/21 03:14:00 florian
|
|
* arm compiler can be compiled; far from being working
|
|
|
|
Revision 1.2 2003/08/20 15:50:12 florian
|
|
* more arm stuff
|
|
|
|
Revision 1.1 2003/07/21 16:35:30 florian
|
|
* very basic stuff for the arm
|
|
}
|