mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-02 18:34:00 +02:00

Switched codegeneration of VFPv2 and VFPv3 to use UAL mnemonics and syntax. Updated VFP code in RTL to use UAL syntax too. Added preliminary ELF support for ARM. Added support for linking of WinCE COFF files. Should work for with a standard ARMv4-I target. git-svn-id: branches/laksen/armiw@29247 -
404 lines
13 KiB
ObjectPascal
404 lines
13 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
Generates ARM 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 narminl;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
node,ninl,ncginl;
|
|
|
|
type
|
|
tarminlinenode = class(tcgInlineNode)
|
|
function first_abs_real: tnode; override;
|
|
function first_sqr_real: tnode; override;
|
|
function first_sqrt_real: tnode; override;
|
|
{ atn,sin,cos,lgn isn't supported by the linux fpe
|
|
function first_arctan_real: tnode; override;
|
|
function first_ln_real: tnode; override;
|
|
function first_cos_real: tnode; override;
|
|
function first_sin_real: tnode; override;
|
|
}
|
|
procedure second_abs_real; override;
|
|
procedure second_sqr_real; override;
|
|
procedure second_sqrt_real; override;
|
|
{ atn,sin,cos,lgn isn't supported by the linux fpe
|
|
procedure second_arctan_real; override;
|
|
procedure second_ln_real; override;
|
|
procedure second_cos_real; override;
|
|
procedure second_sin_real; override;
|
|
}
|
|
procedure second_prefetch; override;
|
|
procedure second_abs_long; override;
|
|
private
|
|
procedure load_fpu_location(out singleprec: boolean);
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
globtype,verbose,globals,
|
|
cpuinfo, defutil,symdef,aasmdata,aasmcpu,
|
|
cgbase,cgutils,pass_1,pass_2,
|
|
cpubase,ncgutil,cgobj,cgcpu, hlcgobj;
|
|
|
|
{*****************************************************************************
|
|
tarminlinenode
|
|
*****************************************************************************}
|
|
|
|
procedure tarminlinenode.load_fpu_location(out singleprec: boolean);
|
|
begin
|
|
secondpass(left);
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
begin
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,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;
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16,
|
|
fpu_fpv4_s16:
|
|
begin
|
|
hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
|
|
location_copy(location,left.location);
|
|
if left.location.loc=LOC_CMMREGISTER then
|
|
begin
|
|
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
|
|
location.loc := LOC_MMREGISTER;
|
|
end;
|
|
end;
|
|
fpu_soft:
|
|
begin
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
|
|
location_copy(location,left.location);
|
|
end
|
|
else
|
|
internalerror(2009111801);
|
|
end;
|
|
singleprec:=tfloatdef(left.resultdef).floattype=s32real;
|
|
end;
|
|
|
|
|
|
function tarminlinenode.first_abs_real : tnode;
|
|
begin
|
|
if (cs_fp_emulation in current_settings.moduleswitches) then
|
|
begin
|
|
firstpass(left);
|
|
expectloc:=LOC_REGISTER;
|
|
first_abs_real:=nil;
|
|
end
|
|
else
|
|
begin
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
expectloc:=LOC_FPUREGISTER;
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16:
|
|
expectloc:=LOC_MMREGISTER;
|
|
fpu_fpv4_s16:
|
|
begin
|
|
if tfloatdef(left.resultdef).floattype=s32real then
|
|
expectloc:=LOC_MMREGISTER
|
|
else
|
|
exit(inherited first_abs_real);
|
|
end;
|
|
else
|
|
internalerror(2009112401);
|
|
end;
|
|
first_abs_real:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tarminlinenode.first_sqr_real : tnode;
|
|
begin
|
|
if (cs_fp_emulation in current_settings.moduleswitches) then
|
|
result:=inherited first_sqr_real
|
|
else
|
|
begin
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
expectloc:=LOC_FPUREGISTER;
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16:
|
|
expectloc:=LOC_MMREGISTER;
|
|
fpu_fpv4_s16:
|
|
begin
|
|
if tfloatdef(left.resultdef).floattype=s32real then
|
|
expectloc:=LOC_MMREGISTER
|
|
else
|
|
exit(inherited first_sqr_real);
|
|
end;
|
|
else
|
|
internalerror(2009112402);
|
|
end;
|
|
first_sqr_real:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tarminlinenode.first_sqrt_real : tnode;
|
|
begin
|
|
if cs_fp_emulation in current_settings.moduleswitches then
|
|
result:=inherited first_sqrt_real
|
|
else
|
|
begin
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
expectloc:=LOC_FPUREGISTER;
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16:
|
|
expectloc:=LOC_MMREGISTER;
|
|
fpu_fpv4_s16:
|
|
begin
|
|
if tfloatdef(left.resultdef).floattype=s32real then
|
|
expectloc:=LOC_MMREGISTER
|
|
else
|
|
exit(inherited first_sqrt_real);
|
|
end;
|
|
else
|
|
internalerror(2009112403);
|
|
end;
|
|
first_sqrt_real := nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ atn,sin,cos,lgn isn't supported by the linux fpe
|
|
function tarminlinenode.first_arctan_real: tnode;
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function tarminlinenode.first_ln_real: tnode;
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
result:=nil;
|
|
end;
|
|
|
|
function tarminlinenode.first_cos_real: tnode;
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function tarminlinenode.first_sin_real: tnode;
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
result:=nil;
|
|
end;
|
|
}
|
|
|
|
|
|
procedure tarminlinenode.second_abs_real;
|
|
var
|
|
singleprec: boolean;
|
|
pf: TOpPostfix;
|
|
begin
|
|
load_fpu_location(singleprec);
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_ABS,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16:
|
|
begin
|
|
if singleprec then
|
|
pf:=PF_F32
|
|
else
|
|
pf:=PF_F64;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register),pf));
|
|
end;
|
|
fpu_fpv4_s16:
|
|
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register), PF_F32));
|
|
fpu_soft:
|
|
begin
|
|
if singleprec then
|
|
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_32,tcgint($7fffffff),location.register)
|
|
else
|
|
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_32,tcgint($7fffffff),location.registerhi);
|
|
end
|
|
else
|
|
internalerror(2009111402);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tarminlinenode.second_sqr_real;
|
|
var
|
|
singleprec: boolean;
|
|
pf: TOpPostfix;
|
|
begin
|
|
load_fpu_location(singleprec);
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_MUF,location.register,left.location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16:
|
|
begin
|
|
if singleprec then
|
|
pf:=PF_F32
|
|
else
|
|
pf:=PF_F64;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register),pf));
|
|
end;
|
|
fpu_fpv4_s16:
|
|
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register), PF_F32));
|
|
else
|
|
internalerror(2009111403);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tarminlinenode.second_sqrt_real;
|
|
var
|
|
singleprec: boolean;
|
|
op: TAsmOp;
|
|
begin
|
|
load_fpu_location(singleprec);
|
|
case current_settings.fputype of
|
|
fpu_fpa,
|
|
fpu_fpa10,
|
|
fpu_fpa11:
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_SQT,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
fpu_vfpv2,
|
|
fpu_vfpv3,
|
|
fpu_vfpv3_d16,
|
|
fpu_fpv4_s16:
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register));
|
|
else
|
|
internalerror(2009111402);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ atn, sin, cos, lgn isn't supported by the linux fpe
|
|
procedure tarminlinenode.second_arctan_real;
|
|
begin
|
|
load_fpu_location;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_ATN,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
end;
|
|
|
|
|
|
procedure tarminlinenode.second_ln_real;
|
|
begin
|
|
load_fpu_location;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_LGN,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
end;
|
|
|
|
procedure tarminlinenode.second_cos_real;
|
|
begin
|
|
load_fpu_location;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_COS,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
end;
|
|
|
|
|
|
procedure tarminlinenode.second_sin_real;
|
|
begin
|
|
load_fpu_location;
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_SIN,location.register,left.location.register),get_fpu_postfix(resultdef)));
|
|
end;
|
|
}
|
|
|
|
procedure tarminlinenode.second_prefetch;
|
|
var
|
|
ref : treference;
|
|
r : tregister;
|
|
begin
|
|
if not(GenerateThumbCode) and (CPUARM_HAS_EDSP in cpu_capabilities[current_settings.cputype]) then
|
|
begin
|
|
secondpass(left);
|
|
case left.location.loc of
|
|
LOC_CREFERENCE,
|
|
LOC_REFERENCE:
|
|
begin
|
|
r:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
|
|
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,r);
|
|
reference_reset_base(ref,r,0,left.location.reference.alignment);
|
|
{ since the address might be nil we can't use ldr for older cpus }
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_PLD,ref));
|
|
end;
|
|
else
|
|
internalerror(200402021);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure tarminlinenode.second_abs_long;
|
|
var
|
|
opsize : tcgsize;
|
|
hp : taicpu;
|
|
begin
|
|
if GenerateThumbCode then
|
|
begin
|
|
inherited second_abs_long;
|
|
exit;
|
|
end;
|
|
|
|
secondpass(left);
|
|
opsize:=def_cgsize(left.resultdef);
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
|
|
location:=left.location;
|
|
location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
|
|
|
|
cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
|
|
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MOV,location.register,left.location.register), PF_S));
|
|
|
|
if GenerateThumb2Code then
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_cond(A_IT,C_MI));
|
|
|
|
current_asmdata.CurrAsmList.concat(setcondition(taicpu.op_reg_reg_const(A_RSB,location.register,location.register, 0), C_MI));
|
|
|
|
cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
|
|
end;
|
|
|
|
begin
|
|
cinlinenode:=tarminlinenode;
|
|
end.
|