diff --git a/compiler/arm/cgcpu.pas b/compiler/arm/cgcpu.pas index a49a0d4038..653bd6f437 100644 --- a/compiler/arm/cgcpu.pas +++ b/compiler/arm/cgcpu.pas @@ -112,6 +112,9 @@ unit cgcpu; { clear out potential overflow bits from 8 or 16 bit operations } { the upper 24/16 bits of a register after an operation } procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister); + + { mla for thumb requires that none of the registers is equal to r13/r15, this method ensures this } + procedure safe_mla(list: TAsmList;op1,op2,op3,op4 : TRegister); end; { tcgarm is shared between normal arm and thumb-2 } @@ -3191,6 +3194,30 @@ unit cgcpu; end; + procedure tbasecgarm.safe_mla(list : TAsmList; op1,op2,op3,op4 : TRegister); + + procedure checkreg(var reg : TRegister); + var + tmpreg : TRegister; + begin + if ((current_settings.cputype in cpu_thumb+cpu_thumb2) and (getsupreg(reg)=RS_R13)) or + (getsupreg(reg)=RS_R15) then + begin + tmpreg:=getintregister(list,OS_INT); + a_load_reg_reg(list,OS_INT,OS_INT,reg,tmpreg); + reg:=tmpreg; + end; + end; + + begin + checkreg(op1); + checkreg(op2); + checkreg(op3); + checkreg(op4); + list.concat(taicpu.op_reg_reg_reg_reg(A_MLA,op1,op2,op3,op4)); + end; + + procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64); begin case op of diff --git a/compiler/arm/narmadd.pas b/compiler/arm/narmadd.pas index 8cdc86492a..88f453c907 100644 --- a/compiler/arm/narmadd.pas +++ b/compiler/arm/narmadd.pas @@ -53,7 +53,7 @@ interface defutil,htypechk,cgbase,cgutils, cpuinfo,pass_1,pass_2,procinfo, ncon,nadd,ncnv,ncal,nmat, - ncgutil,cgobj, + ncgutil,cgobj,cgcpu, hlcgobj ; @@ -509,7 +509,7 @@ interface tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_32); asmList.concat(taicpu.op_reg_reg_reg(A_MUL,tmpreg,ll.reglo,rl.reghi)); asmList.concat(taicpu.op_reg_reg_reg_reg(A_UMULL,res.reglo,res.reghi,rl.reglo,ll.reglo)); - asmList.concat(taicpu.op_reg_reg_reg_reg(A_MLA,tmpreg,rl.reglo,ll.reghi,tmpreg)); + tbasecgarm(cg).safe_mla(asmList,tmpreg,rl.reglo,ll.reghi,tmpreg); asmList.concat(taicpu.op_reg_reg_reg(A_ADD,res.reghi,tmpreg,res.reghi)); end else diff --git a/compiler/arm/narmmem.pas b/compiler/arm/narmmem.pas index 999f6e919f..f81bddc590 100644 --- a/compiler/arm/narmmem.pas +++ b/compiler/arm/narmmem.pas @@ -42,7 +42,7 @@ interface implementation uses - cutils,verbose,globals,aasmdata,aasmcpu,cgobj, + cutils,verbose,globals,aasmdata,aasmcpu,cgobj,cgcpu, cpuinfo, cgutils, procinfo; @@ -84,7 +84,7 @@ implementation begin hreg:=cg.getaddressregister(current_asmdata.CurrAsmList); cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_ADDR,l,hreg); - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MLA,hreg,maybe_const_reg,hreg,location.reference.base)); + tbasecgarm(cg).safe_mla(current_asmdata.CurrAsmList,hreg,maybe_const_reg,hreg,location.reference.base); location.reference.base:=hreg; { update alignment } if (location.reference.alignment=0) then @@ -95,7 +95,7 @@ implementation begin hreg:=cg.getaddressregister(current_asmdata.CurrAsmList); cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_ADDR,l,hreg); - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MLA,hreg,maybe_const_reg,hreg,location.reference.index)); + tbasecgarm(cg).safe_mla(current_asmdata.CurrAsmList,hreg,maybe_const_reg,hreg,location.reference.index); location.reference.base:=hreg; location.reference.index:=NR_NO; { update alignment } diff --git a/compiler/arm/rgcpu.pas b/compiler/arm/rgcpu.pas index 031563e95d..aa59b93137 100644 --- a/compiler/arm/rgcpu.pas +++ b/compiler/arm/rgcpu.pas @@ -121,6 +121,24 @@ unit rgcpu; end; end; end; + A_MLA, + A_MUL: + begin + if current_settings.cputype