diff options
Diffstat (limited to 'compiler/arm/cgcpu.pas')
-rw-r--r-- | compiler/arm/cgcpu.pas | 93 |
1 files changed, 78 insertions, 15 deletions
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; |