diff options
Diffstat (limited to 'compiler/arm')
-rw-r--r-- | compiler/arm/aasmcpu.pas | 20 | ||||
-rw-r--r-- | compiler/arm/aoptcpu.pas | 102 | ||||
-rw-r--r-- | compiler/arm/aoptcpub.pas | 13 | ||||
-rw-r--r-- | compiler/arm/cgcpu.pas | 93 | ||||
-rw-r--r-- | compiler/arm/cpuelf.pas | 44 | ||||
-rw-r--r-- | compiler/arm/cpuinfo.pas | 7 | ||||
-rw-r--r-- | compiler/arm/narmadd.pas | 46 | ||||
-rw-r--r-- | compiler/arm/narmset.pas | 15 | ||||
-rw-r--r-- | compiler/arm/raarmgas.pas | 1 | ||||
-rw-r--r-- | compiler/arm/rgcpu.pas | 14 |
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; |