summaryrefslogtreecommitdiff
path: root/compiler/arm
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/arm')
-rw-r--r--compiler/arm/aasmcpu.pas20
-rw-r--r--compiler/arm/aoptcpu.pas102
-rw-r--r--compiler/arm/aoptcpub.pas13
-rw-r--r--compiler/arm/cgcpu.pas93
-rw-r--r--compiler/arm/cpuelf.pas44
-rw-r--r--compiler/arm/cpuinfo.pas7
-rw-r--r--compiler/arm/narmadd.pas46
-rw-r--r--compiler/arm/narmset.pas15
-rw-r--r--compiler/arm/raarmgas.pas1
-rw-r--r--compiler/arm/rgcpu.pas14
10 files changed, 293 insertions, 62 deletions
diff --git a/compiler/arm/aasmcpu.pas b/compiler/arm/aasmcpu.pas
index 58b8010226..1086f17867 100644
--- a/compiler/arm/aasmcpu.pas
+++ b/compiler/arm/aasmcpu.pas
@@ -212,7 +212,7 @@ uses
function is_same_reg_move(regtype: Tregistertype):boolean; override;
function spilling_get_operation_type(opnr: longint): topertype;override;
-
+ function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override;
{ assembler }
public
{ the next will reset all instructions that can change in pass 2 }
@@ -777,6 +777,15 @@ implementation
end;
+ function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;
+ begin
+ result := operand_read;
+ if (oper[opnr]^.ref^.base = reg) and
+ (oper[opnr]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
+ result := operand_readwrite;
+ end;
+
+
procedure BuildInsTabCache;
var
i : longint;
@@ -1055,15 +1064,16 @@ implementation
(tai(hp).typ=ait_instruction) then
begin
case taicpu(hp).opcode of
- A_BX,
+ A_MOV,
A_LDR,
A_ADD:
{ approximation if we hit a case jump table }
if ((taicpu(hp).opcode in [A_ADD,A_LDR]) and not(GenerateThumbCode or GenerateThumb2Code) and
(taicpu(hp).oper[0]^.typ=top_reg) and
(taicpu(hp).oper[0]^.reg=NR_PC)) or
- ((taicpu(hp).opcode=A_BX) and (GenerateThumbCode) and
- (taicpu(hp).oper[0]^.typ=top_reg))
+ ((taicpu(hp).opcode=A_MOV) and (GenerateThumbCode) and
+ (taicpu(hp).oper[0]^.typ=top_reg) and
+ (taicpu(hp).oper[0]^.reg=NR_PC))
then
begin
penalty:=multiplier;
@@ -1858,7 +1868,7 @@ implementation
ot:=OT_SHIFTEROP;
end;
else
- internalerror(200402261);
+ internalerror(2004022623);
end;
end;
end;
diff --git a/compiler/arm/aoptcpu.pas b/compiler/arm/aoptcpu.pas
index 229a63816f..2cca31ec52 100644
--- a/compiler/arm/aoptcpu.pas
+++ b/compiler/arm/aoptcpu.pas
@@ -30,7 +30,7 @@ Unit aoptcpu;
Interface
-uses cgbase, cpubase, aasmtai, aasmcpu,aopt, aoptobj;
+uses cgbase, cgutils, cpubase, aasmtai, aasmcpu,aopt, aoptobj;
Type
TCpuAsmOptimizer = class(TAsmOptimizer)
@@ -49,7 +49,8 @@ Type
change in program flow.
If there is none, it returns false and
sets p1 to nil }
- Function GetNextInstructionUsingReg(Current: tai; Var Next: tai;reg : TRegister): Boolean;
+ Function GetNextInstructionUsingReg(Current: tai; Out Next: tai; reg: TRegister): Boolean;
+ Function GetNextInstructionUsingRef(Current: tai; Out Next: tai; const ref: TReference; StopOnStore: Boolean = true): Boolean;
{ outputs a debug message into the assembler file }
procedure DebugMsg(const s: string; p: tai);
@@ -79,7 +80,7 @@ Implementation
cutils,verbose,globtype,globals,
systems,
cpuinfo,
- cgobj,cgutils,procinfo,
+ cgobj,procinfo,
aasmbase,aasmdata;
function CanBeCond(p : tai) : boolean;
@@ -317,15 +318,46 @@ Implementation
RegLoadedWithNewValue(reg,p);
end;
-
function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
- var Next: tai; reg: TRegister): Boolean;
+ Out Next: tai; reg: TRegister): Boolean;
begin
Next:=Current;
repeat
Result:=GetNextInstruction(Next,Next);
- until not(cs_opt_level3 in current_settings.optimizerswitches) or not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
- (is_calljmp(taicpu(Next).opcode)) or (RegInInstruction(NR_PC,Next));
+ until not (Result) or
+ not(cs_opt_level3 in current_settings.optimizerswitches) or
+ (Next.typ<>ait_instruction) or
+ RegInInstruction(reg,Next) or
+ is_calljmp(taicpu(Next).opcode) or
+ RegModifiedByInstruction(NR_PC,Next);
+ end;
+
+ function TCpuAsmOptimizer.GetNextInstructionUsingRef(Current: tai;
+ Out Next: tai; const ref: TReference; StopOnStore: Boolean = true): Boolean;
+ begin
+ Next:=Current;
+ repeat
+ Result:=GetNextInstruction(Next,Next);
+ if Result and
+ (Next.typ=ait_instruction) and
+ (taicpu(Next).opcode in [A_LDR, A_STR]) and
+ (
+ ((taicpu(Next).ops = 2) and
+ (taicpu(Next).oper[1]^.typ = top_ref) and
+ RefsEqual(taicpu(Next).oper[1]^.ref^,ref)) or
+ ((taicpu(Next).ops = 3) and { LDRD/STRD }
+ (taicpu(Next).oper[2]^.typ = top_ref) and
+ RefsEqual(taicpu(Next).oper[2]^.ref^,ref))
+ ) then
+ {We've found an instruction LDR or STR with the same reference}
+ exit;
+ until not(Result) or
+ (Next.typ<>ait_instruction) or
+ not(cs_opt_level3 in current_settings.optimizerswitches) or
+ is_calljmp(taicpu(Next).opcode) or
+ (StopOnStore and (taicpu(Next).opcode in [A_STR, A_STM])) or
+ RegModifiedByInstruction(NR_PC,Next);
+ Result:=false;
end;
{$ifdef DEBUG_AOPTCPU}
@@ -482,7 +514,8 @@ Implementation
hp1 : tai;
begin
Result:=false;
- if (p.oper[1]^.ref^.addressmode=AM_OFFSET) and
+ if (p.oper[1]^.typ = top_ref) and
+ (p.oper[1]^.ref^.addressmode=AM_OFFSET) and
(p.oper[1]^.ref^.index=NR_NO) and
(p.oper[1]^.ref^.offset=0) and
GetNextInstructionUsingReg(p, hp1, p.oper[1]^.ref^.base) and
@@ -538,6 +571,7 @@ Implementation
TmpUsedRegs: TAllUsedRegs;
tempop: tasmop;
oldreg: tregister;
+ dealloc: tai_regalloc;
function IsPowerOf2(const value: DWord): boolean; inline;
begin
@@ -607,12 +641,17 @@ Implementation
str reg1,ref
mov reg2,reg1
}
- if (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
+ if (taicpu(p).oper[1]^.typ = top_ref) and
+ (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
(taicpu(p).oppostfix=PF_None) and
- GetNextInstruction(p,hp1) and
- MatchInstruction(hp1, A_LDR, [taicpu(p).condition, C_None], [PF_None]) and
- RefsEqual(taicpu(p).oper[1]^.ref^,taicpu(hp1).oper[1]^.ref^) and
- (taicpu(hp1).oper[1]^.ref^.addressmode=AM_OFFSET) then
+ (taicpu(p).condition=C_None) and
+ GetNextInstructionUsingRef(p,hp1,taicpu(p).oper[1]^.ref^) and
+ MatchInstruction(hp1, A_LDR, [taicpu(p).condition], [PF_None]) and
+ (taicpu(hp1).oper[1]^.typ=top_ref) and
+ (taicpu(hp1).oper[1]^.ref^.addressmode=AM_OFFSET) and
+ not(RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
+ ((taicpu(hp1).oper[1]^.ref^.index=NR_NO) or not (RegModifiedBetween(taicpu(hp1).oper[1]^.ref^.index, p, hp1))) and
+ ((taicpu(hp1).oper[1]^.ref^.base=NR_NO) or not (RegModifiedBetween(taicpu(hp1).oper[1]^.ref^.base, p, hp1))) then
begin
if taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg then
begin
@@ -633,7 +672,7 @@ Implementation
str reg1,ref
str reg2,ref
into
- strd reg1,ref
+ strd reg1,reg2,ref
}
else if (GenerateARMCode or GenerateThumb2Code) and
(CPUARM_HAS_EDSP in cpu_capabilities[current_settings.cputype]) and
@@ -654,6 +693,9 @@ Implementation
begin
DebugMsg('Peephole StrStr2Strd done', p);
taicpu(p).oppostfix:=PF_D;
+ taicpu(p).loadref(2,taicpu(p).oper[1]^.ref^);
+ taicpu(p).loadreg(1, taicpu(hp1).oper[0]^.reg);
+ taicpu(p).ops:=3;
asml.remove(hp1);
hp1.free;
result:=true;
@@ -667,7 +709,8 @@ Implementation
ldr reg2,ref
into ...
}
- if (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
+ if (taicpu(p).oper[1]^.typ = top_ref) and
+ (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
GetNextInstruction(p,hp1) and
{ ldrd is not allowed here }
MatchInstruction(hp1, A_LDR, [taicpu(p).condition, C_None], [taicpu(p).oppostfix,PF_None]-[PF_D]) then
@@ -700,7 +743,7 @@ Implementation
end
{
...
- ldrd reg1,ref
+ ldrd reg1,reg1+1,ref
}
else if (GenerateARMCode or GenerateThumb2Code) and
(CPUARM_HAS_EDSP in cpu_capabilities[current_settings.cputype]) and
@@ -718,6 +761,9 @@ Implementation
AlignedToQWord(taicpu(p).oper[1]^.ref^) then
begin
DebugMsg('Peephole LdrLdr2Ldrd done', p);
+ taicpu(p).loadref(2,taicpu(p).oper[1]^.ref^);
+ taicpu(p).loadreg(1, taicpu(hp1).oper[0]^.reg);
+ taicpu(p).ops:=3;
taicpu(p).oppostfix:=PF_D;
asml.remove(hp1);
hp1.free;
@@ -1200,6 +1246,7 @@ Implementation
(taicpu(p).oppostfix = PF_NONE) and
GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
MatchInstruction(hp1, [A_LDR, A_STR], [taicpu(p).condition], []) and
+ (taicpu(hp1).oper[1]^.typ = top_ref) and
{ We can change the base register only when the instruction uses AM_OFFSET }
((taicpu(hp1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) or
((taicpu(hp1).oper[1]^.ref^.addressmode = AM_OFFSET) and
@@ -1222,6 +1269,13 @@ Implementation
if taicpu(hp1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
taicpu(hp1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
+ dealloc:=FindRegDeAlloc(taicpu(p).oper[1]^.reg, taicpu(p.Next));
+ if Assigned(dealloc) then
+ begin
+ asml.remove(dealloc);
+ asml.InsertAfter(dealloc,hp1);
+ end;
+
GetNextInstruction(p, hp1);
asml.remove(p);
p.free;
@@ -1583,13 +1637,14 @@ Implementation
and reg1,reg0,2^n-1
mov reg2,reg1, lsl imm1
=>
- mov reg2,reg1, lsl imm1
+ mov reg2,reg0, lsl imm1
if imm1>i
}
- else if i>32-taicpu(hp1).oper[2]^.shifterop^.shiftimm then
+ else if (i>32-taicpu(hp1).oper[2]^.shifterop^.shiftimm) and
+ not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) then
begin
DebugMsg('Peephole AndLsl2Lsl done', p);
- taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[0]^.reg;
+ taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
GetNextInstruction(p, hp1);
asml.Remove(p);
p.free;
@@ -1616,6 +1671,7 @@ Implementation
while GetNextInstructionUsingReg(hp1, hp1, taicpu(p).oper[0]^.reg) and
{ we cannot check NR_DEFAULTFLAGS for modification yet so don't allow a condition }
MatchInstruction(hp1, [A_LDR, A_STR], [C_None], []) and
+ (taicpu(hp1).oper[1]^.typ = top_ref) and
(taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
{ don't optimize if the register is stored/overwritten }
(taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[1]^.reg) and
@@ -2389,7 +2445,7 @@ Implementation
begin
result:=true;
- list:=TAsmList.create_without_marker;
+ list:=TAsmList.create;
p:=BlockStart;
while p<>BlockEnd Do
begin
@@ -2410,6 +2466,7 @@ Implementation
) or
{ try to prove that the memory accesses don't overlapp }
((taicpu(p).opcode in [A_STRB,A_STRH,A_STR]) and
+ (taicpu(p).oper[1]^.typ = top_ref) and
(taicpu(p).oper[1]^.ref^.base=taicpu(hp1).oper[1]^.ref^.base) and
(taicpu(p).oppostfix=PF_None) and
(taicpu(hp1).oppostfix=PF_None) and
@@ -2435,7 +2492,10 @@ Implementation
{ first instruction might not change the register used as index }
((taicpu(hp1).oper[1]^.ref^.index=NR_NO) or
not(RegModifiedByInstruction(taicpu(hp1).oper[1]^.ref^.index,p))
- ) then
+ ) and
+ { if we modify the basereg AND the first instruction used that reg, we can not schedule }
+ ((taicpu(hp1).oper[1]^.ref^.addressmode = AM_OFFSET) or
+ not(instructionLoadsFromReg(taicpu(hp1).oper[1]^.ref^.base,p))) then
begin
hp3:=tai(p.Previous);
hp5:=tai(p.next);
diff --git a/compiler/arm/aoptcpub.pas b/compiler/arm/aoptcpub.pas
index aa60bfd624..28451ca028 100644
--- a/compiler/arm/aoptcpub.pas
+++ b/compiler/arm/aoptcpub.pas
@@ -124,11 +124,14 @@ Implementation
begin
result:=false;
for i:=0 to taicpu(p1).ops-1 do
- if (taicpu(p1).oper[i]^.typ=top_reg) and (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then
- begin
- result:=true;
- exit;
- end;
+ case taicpu(p1).oper[i]^.typ of
+ top_reg:
+ if (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then
+ exit(true);
+ top_ref:
+ if (taicpu(p1).spilling_get_operation_type_ref(i,Reg)<>operand_read) then
+ exit(true);
+ end;
end;
End.
diff --git a/compiler/arm/cgcpu.pas b/compiler/arm/cgcpu.pas
index a41aef9a0b..82884fae57 100644
--- a/compiler/arm/cgcpu.pas
+++ b/compiler/arm/cgcpu.pas
@@ -71,6 +71,8 @@ unit cgcpu;
procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
+ procedure g_profilecode(list : TAsmList); override;
+
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
procedure g_maybe_got_init(list : TAsmList); override;
@@ -182,6 +184,8 @@ unit cgcpu;
procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
function handle_load_store(list: TAsmList; op: tasmop; oppostfix: toppostfix; reg: tregister; ref: treference): treference; override;
+
+ procedure g_external_wrapper(list : TAsmList; procdef : tprocdef; const externalname : string); override;
end;
tthumbcg64farm = class(tbasecg64farm)
@@ -1794,6 +1798,16 @@ unit cgcpu;
list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
end;
+ procedure tbasecgarm.g_profilecode(list : TAsmList);
+ begin
+ if target_info.system = system_arm_linux then
+ begin
+ list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R14]));
+ a_call_name(list,'__gnu_mcount_nc',false);
+ end
+ else
+ internalerror(2014091201);
+ end;
procedure tbasecgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
var
@@ -3201,6 +3215,7 @@ unit cgcpu;
if (href.offset in [0..124]) and ((href.offset mod 4)=0) then
begin
list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
+ list.concat(taicpu.op_reg_reg(A_MOV,NR_R0,NR_R12));
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
@@ -3218,20 +3233,21 @@ unit cgcpu;
tmpref.symbol:=l;
tmpref.base:=NR_PC;
list.concat(taicpu.op_reg_ref(A_LDR,NR_R1,tmpref));
+ list.concat(taicpu.op_reg_reg(A_MOV,NR_R0,NR_R12));
href.offset:=0;
+ href.base:=NR_R0;
href.index:=NR_R1;
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0,RS_R1]));
end;
- list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
end
else
begin
reference_reset_base(href,NR_R12,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
- list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
end;
+ list.concat(taicpu.op_reg(A_BX,NR_R12));
end;
var
@@ -3248,6 +3264,9 @@ unit cgcpu;
if procdef.owner.symtabletype<>ObjectSymtable then
Internalerror(200109191);
+ if GenerateThumbCode or GenerateThumb2Code then
+ list.concat(tai_thumb_func.create);
+
make_global:=false;
if (not current_module.is_unit) or
create_smartlink or
@@ -3293,7 +3312,7 @@ unit cgcpu;
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_R0);
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
- list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
+ list.concat(taicpu.op_reg(A_BX,NR_R12));
end
else
list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
@@ -4050,18 +4069,36 @@ unit cgcpu;
tmpreg : TRegister;
begin
href:=ref;
- if (op in [A_STR,A_STRB,A_STRH]) and
- (abs(ref.offset)>124) then
- begin
- tmpreg:=getintregister(list,OS_ADDR);
- a_loadaddr_ref_reg(list,ref,tmpreg);
-
- reference_reset_base(href,tmpreg,0,ref.alignment);
- end
- else if (op=A_LDR) and
- (oppostfix in [PF_None]) and
- (ref.base<>NR_STACK_POINTER_REG) and
- (abs(ref.offset)>124) then
+ if { LDR/STR limitations }
+ (
+ (((op=A_LDR) and (oppostfix=PF_None)) or
+ ((op=A_STR) and (oppostfix=PF_None))) and
+ (ref.base<>NR_STACK_POINTER_REG) and
+ (abs(ref.offset)>124)
+ ) or
+ { LDRB/STRB limitations }
+ (
+ (((op=A_LDR) and (oppostfix=PF_B)) or
+ ((op=A_LDRB) and (oppostfix=PF_None)) or
+ ((op=A_STR) and (oppostfix=PF_B)) or
+ ((op=A_STRB) and (oppostfix=PF_None))) and
+ ((ref.base=NR_STACK_POINTER_REG) or
+ (ref.index=NR_STACK_POINTER_REG) or
+ (abs(ref.offset)>31)
+ )
+ ) or
+ { LDRH/STRH limitations }
+ (
+ (((op=A_LDR) and (oppostfix=PF_H)) or
+ ((op=A_LDRH) and (oppostfix=PF_None)) or
+ ((op=A_STR) and (oppostfix=PF_H)) or
+ ((op=A_STRH) and (oppostfix=PF_None))) and
+ ((ref.base=NR_STACK_POINTER_REG) or
+ (ref.index=NR_STACK_POINTER_REG) or
+ (abs(ref.offset)>62) or
+ ((abs(ref.offset) mod 2)<>0)
+ )
+ ) then
begin
tmpreg:=getintregister(list,OS_ADDR);
a_loadaddr_ref_reg(list,ref,tmpreg);
@@ -4274,6 +4311,32 @@ unit cgcpu;
end;
+ procedure tthumbcgarm.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
+ var
+ tmpref : treference;
+ l : tasmlabel;
+ begin
+ { there is no branch instruction on thumb which allows big distances and which leaves LR as it is
+ and which allows to switch the instruction set }
+
+ { create const entry }
+ reference_reset(tmpref,4);
+ current_asmdata.getjumplabel(l);
+ tmpref.symbol:=l;
+ tmpref.base:=NR_PC;
+ list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
+ list.concat(taicpu.op_reg_ref(A_LDR,NR_R0,tmpref));
+ list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
+ list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
+ list.concat(taicpu.op_reg(A_BX,NR_R12));
+
+ { append const entry }
+ list.Concat(tai_align.Create(4));
+ list.Concat(tai_label.create(l));
+ list.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(externalname)));
+ end;
+
+
procedure tthumb2cgarm.init_register_allocators;
begin
inherited init_register_allocators;
diff --git a/compiler/arm/cpuelf.pas b/compiler/arm/cpuelf.pas
index f42ea3d9fd..c912955f89 100644
--- a/compiler/arm/cpuelf.pas
+++ b/compiler/arm/cpuelf.pas
@@ -561,6 +561,7 @@ implementation
rotation:longint;
residual,g_n:longword;
curloc: aword;
+ bit_S,bit_I1,bit_I2: aint;
begin
data:=objsec.data;
for i:=0 to objsec.ObjRelocations.Count-1 do
@@ -660,7 +661,16 @@ implementation
2) when target is unresolved weak symbol, CALL must be changed to NOP,
while JUMP24 behavior is unspecified. }
tmp:=sarlongint((address and $00FFFFFF) shl 8,6);
- tmp:=tmp+relocval-curloc;
+ tmp:=tmp+relocval;
+ if odd(tmp) then { dest is Thumb? }
+ begin
+ if (reltyp=R_ARM_CALL) then
+ { change BL to BLX, dest bit 1 goes to instruction bit 24 }
+ address:=(address and $FE000000) or (((tmp-curloc) and 2) shl 23) or $10000000
+ else
+ InternalError(2014092001);
+ end;
+ tmp:=tmp-curloc;
// TODO: check overflow
address:=(address and $FF000000) or ((tmp and $3FFFFFE) shr 2);
end;
@@ -829,6 +839,38 @@ implementation
address:=address or (1 shl 23);
end;
+ R_ARM_THM_CALL:
+ begin
+ if (not ElfTarget.relocs_use_addend) then
+ begin
+ address:=((address and $ffff) shl 16) or word(address shr 16);
+ bit_S:=(address shr 26) and 1;
+ bit_I1:=(bit_S xor ((address shr 13) and 1)) xor 1;
+ bit_I2:=(bit_S xor ((address shr 11) and 1)) xor 1;
+ tmp:=((-bit_S) shl 24) or (bit_I1 shl 23) or (bit_I2 shl 22) or (((address shr 16) and $3ff) shl 12) or ((address and $7ff) shl 1);
+ end
+ else { TODO: must read the instruction anyway }
+ tmp:=address;
+ tmp:=tmp+relocval; { dest address }
+ if odd(tmp) then { if it's Thumb code, change possible BLX to BL }
+ address:=address or $1800;
+ tmp:=tmp-curloc; { now take PC-relative }
+ { TODO: overflow check, different limit for Thumb and Thumb-2 }
+
+ { now encode this mess back }
+ if (address and $5000)=$4000 then
+ tmp:=(tmp+2) and (not 3);
+
+ bit_S:=(tmp shr 31) and 1;
+ address:=(address and $F800D000) or
+ (bit_S shl 26) or
+ (((tmp shr 12) and $3ff) shl 16) or
+ ((tmp shr 1) and $7FF) or
+ ((((tmp shr 23) and 1) xor 1 xor bit_S) shl 13) or
+ ((((tmp shr 22) and 1) xor 1 xor bit_S) shl 11);
+ address:=((address and $ffff) shl 16) or word(address shr 16);
+ end;
+
R_ARM_TLS_IE32:
begin
relocval:=relocval-tlsseg.mempos+align_aword(TCB_SIZE,tlsseg.align);
diff --git a/compiler/arm/cpuinfo.pas b/compiler/arm/cpuinfo.pas
index 52277fccea..05ea89d9e3 100644
--- a/compiler/arm/cpuinfo.pas
+++ b/compiler/arm/cpuinfo.pas
@@ -21,6 +21,9 @@ Interface
Type
bestreal = double;
+{$if FPC_FULLVERSION>20700}
+ bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
ts32real = single;
ts64real = double;
ts80real = type extended;
@@ -338,8 +341,10 @@ Type
ct_thumb2bare
);
-
Const
+ { Is there support for dealing with multiple microcontrollers available }
+ { for this platform? }
+ ControllerSupport = true;
{# Size of native extended floating point type }
extended_size = 12;
{# Size of a multimedia register }
diff --git a/compiler/arm/narmadd.pas b/compiler/arm/narmadd.pas
index 7083067a42..4e26f71736 100644
--- a/compiler/arm/narmadd.pas
+++ b/compiler/arm/narmadd.pas
@@ -85,6 +85,8 @@ interface
GetResFlags:=F_LT;
gten:
GetResFlags:=F_LE;
+ else
+ internalerror(201408203);
end
else
case NodeType of
@@ -96,6 +98,8 @@ interface
GetResFlags:=F_GT;
gten:
GetResFlags:=F_GE;
+ else
+ internalerror(201408204);
end;
end
else
@@ -110,6 +114,8 @@ interface
GetResFlags:=F_CC;
gten:
GetResFlags:=F_LS;
+ else
+ internalerror(201408205);
end
else
case NodeType of
@@ -121,6 +127,8 @@ interface
GetResFlags:=F_HI;
gten:
GetResFlags:=F_CS;
+ else
+ internalerror(201408206);
end;
end;
end;
@@ -144,6 +152,8 @@ interface
result:=F_GT;
gten:
result:=F_GE;
+ else
+ internalerror(201408207);
end;
end;
@@ -379,13 +389,13 @@ interface
tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
if right.location.loc = LOC_CONSTANT then
begin
- current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_AND,tmpreg,left.location.register,right.location.value));
+ cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_AND,OS_32,right.location.value,left.location.register,tmpreg);
cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,tmpreg,right.location.value));
end
else
begin
- current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_AND,tmpreg,left.location.register,right.location.register));
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,OS_32,left.location.register,right.location.register,tmpreg);
cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,tmpreg,right.location.register));
end;
@@ -403,6 +413,8 @@ interface
oldnodetype : tnodetype;
dummyreg : tregister;
l: tasmlabel;
+ const
+ lt_zero_swapped: array[boolean] of tnodetype = (ltn, gtn);
begin
unsigned:=not(is_signed(left.resultdef)) or
not(is_signed(right.resultdef));
@@ -411,20 +423,34 @@ interface
{ pass_left_right moves possible consts to the right, the only
remaining case with left consts (currency) can take this path too (KB) }
- if (nodetype in [equaln,unequaln]) and
- (right.nodetype=ordconstn) and (tordconstnode(right).value=0) then
+ if (right.nodetype=ordconstn) and
+ (tordconstnode(right).value=0) and
+ ((nodetype in [equaln,unequaln]) or
+ (not(GenerateThumbCode) and is_signed(left.resultdef) and (nodetype = lt_zero_swapped[nf_swapped in Flags]))
+ ) then
begin
location_reset(location,LOC_FLAGS,OS_NO);
- location.resflags:=getresflags(unsigned);
if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
- dummyreg:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
- cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
- if GenerateThumbCode then
- cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reglo,left.location.register64.reghi,dummyreg)
+ cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
+ { Optimize for the common case of int64 < 0 }
+ if nodetype in [ltn, gtn] then
+ begin
+ {Just check for the MSB in reghi to be set or not, this is independed from nf_swapped}
+ location.resflags:=F_NE;
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_TST,left.location.register64.reghi, aint($80000000)));
+ end
else
- current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ORR,dummyreg,left.location.register64.reglo,left.location.register64.reghi),PF_S));
+ begin
+ location.resflags:=getresflags(unsigned);
+ dummyreg:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+
+ if GenerateThumbCode then
+ cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reglo,left.location.register64.reghi,dummyreg)
+ else
+ current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ORR,dummyreg,left.location.register64.reglo,left.location.register64.reghi),PF_S));
+ end;
end
else
begin
diff --git a/compiler/arm/narmset.pas b/compiler/arm/narmset.pas
index 35b34321a3..e1a99f2dbb 100644
--- a/compiler/arm/narmset.pas
+++ b/compiler/arm/narmset.pas
@@ -141,6 +141,7 @@ implementation
procedure tarmcasenode.genjumptable(hp : pcaselabel;min_,max_ : aint);
var
last : TConstExprInt;
+ tmpreg,
basereg,
indexreg : tregister;
href : treference;
@@ -222,7 +223,7 @@ implementation
begin
if cs_create_pic in current_settings.moduleswitches then
internalerror(2013082102);
- cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_ADDR,min_+1,indexreg,indexreg);
+ cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_ADDR,min_,indexreg,indexreg);
current_asmdata.getaddrlabel(tablelabel);
cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,2,indexreg);
@@ -231,9 +232,15 @@ implementation
reference_reset_symbol(href,tablelabel,0,4);
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList, href, basereg);
- cg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_ADD, OS_ADDr, indexreg, basereg);
-
- current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_BX, basereg));
+ reference_reset(href,0);
+ href.base:=basereg;
+ href.index:=indexreg;
+
+ tmpreg:=cg.getintregister(current_asmdata.CurrAsmList, OS_ADDR);
+ cg.a_load_ref_reg(current_asmdata.CurrAsmList, OS_ADDR, OS_ADDR, href, tmpreg);
+
+ { do not use BX here to avoid switching into arm mode }
+ current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_MOV, NR_PC, tmpreg));
cg.a_label(current_asmdata.CurrAsmList,tablelabel);
{ generate jump table }
diff --git a/compiler/arm/raarmgas.pas b/compiler/arm/raarmgas.pas
index 64f330a213..e7de7b8d71 100644
--- a/compiler/arm/raarmgas.pas
+++ b/compiler/arm/raarmgas.pas
@@ -1043,6 +1043,7 @@ Unit raarmgas;
hreg : tregister;
flags : tspecialregflags;
begin
+ hreg:=NR_NO;
case actasmtoken of
AS_REGISTER:
begin
diff --git a/compiler/arm/rgcpu.pas b/compiler/arm/rgcpu.pas
index fdb9e0df9e..ca55f59f2c 100644
--- a/compiler/arm/rgcpu.pas
+++ b/compiler/arm/rgcpu.pas
@@ -290,6 +290,10 @@ unit rgcpu;
if abs(spilltemp.offset)>4095 then
exit;
+ { ldr can't set the flags }
+ if instr.oppostfix=PF_S then
+ exit;
+
if GenerateThumbCode and
(abs(spilltemp.offset)>1020) then
exit;
@@ -304,6 +308,11 @@ unit rgcpu;
(get_alias(getsupreg(oper[0]^.reg))=orgreg) and
(get_alias(getsupreg(oper[1]^.reg))<>orgreg) then
begin
+ { do not replace if we're on Thumb, ldr/str cannot be used with rX>r7 }
+ if GenerateThumbCode and
+ (getsupreg(oper[1]^.reg)>RS_R7) then
+ exit;
+
{ str expects the register in oper[0] }
instr.loadreg(0,oper[1]^.reg);
instr.loadref(1,spilltemp);
@@ -314,6 +323,11 @@ unit rgcpu;
(get_alias(getsupreg(oper[1]^.reg))=orgreg) and
(get_alias(getsupreg(oper[0]^.reg))<>orgreg) then
begin
+ { do not replace if we're on Thumb, ldr/str cannot be used with rX>r7 }
+ if GenerateThumbCode and
+ (getsupreg(oper[0]^.reg)>RS_R7) then
+ exit;
+
instr.loadref(1,spilltemp);
opcode:=A_LDR;
result:=true;