diff --git a/.gitattributes b/.gitattributes index 7af2edd6d1..4ddfb39616 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14945,6 +14945,7 @@ tests/test/tfma1.inc svneol=native#text/plain tests/test/tfma1a64.pp svneol=native#text/pascal tests/test/tfma1arm.pp svneol=native#text/pascal tests/test/tfma1x86.pp svneol=native#text/pascal +tests/test/tfma1xtensa.pp svneol=native#text/pascal tests/test/tforin1.pp svneol=native#text/pascal tests/test/tforin10.pp svneol=native#text/plain tests/test/tforin11.pp svneol=native#text/plain diff --git a/compiler/xtensa/ncpuadd.pas b/compiler/xtensa/ncpuadd.pas index 4e0343df3e..f9177787df 100644 --- a/compiler/xtensa/ncpuadd.pas +++ b/compiler/xtensa/ncpuadd.pas @@ -47,6 +47,7 @@ interface procedure second_cmpfloat;override; procedure second_addfloat;override; procedure second_cmp; + function use_fma: boolean;override; end; implementation @@ -67,6 +68,13 @@ interface TCPUAddNode *****************************************************************************} + function TCPUAddNode.use_fma : boolean; + begin + Result:=is_single(left.resultdef) and is_single(right.resultdef) and + (FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]); + end; + + procedure TCPUAddNode.second_addordinal; var ophigh: tasmop; diff --git a/compiler/xtensa/ncpuinl.pas b/compiler/xtensa/ncpuinl.pas index 75b199502d..3eda0dbde1 100644 --- a/compiler/xtensa/ncpuinl.pas +++ b/compiler/xtensa/ncpuinl.pas @@ -33,6 +33,8 @@ unit ncpuinl; function first_abs_real: tnode; override; procedure second_abs_long; override; procedure second_abs_real; override; + function first_fma: tnode; override; + procedure second_fma; override; end; implementation @@ -48,6 +50,7 @@ unit ncpuinl; hlcgobj, pass_2, cgbase, cgobj, cgutils, + ncal, cpubase; procedure tcpuinlinenode.second_abs_long; @@ -84,6 +87,86 @@ unit ncpuinl; end; + function tcpuinlinenode.first_fma : tnode; + begin + if is_single(resultdef) then + begin + expectloc:=LOC_FPUREGISTER; + Result:=nil; + end + else + Result:=inherited first_fma; + end; + + + procedure tcpuinlinenode.second_fma; + const + op : array[false..true] of TAsmOp = + (A_MADD, + A_MSUB); + + var + paraarray : array[1..3] of tnode; + i : integer; + negproduct : boolean; + oppostfix : TOpPostfix; + ai: taicpu; + begin + if is_single(resultdef)and + (FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) then + begin + negproduct:=false; + paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue; + paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue; + paraarray[3]:=tcallparanode(parameters).paravalue; + + { check if a neg. node can be removed + this is possible because changing the sign of + a floating point number does not affect its absolute + value in any way + } + if paraarray[1].nodetype=unaryminusn then + begin + paraarray[1]:=tunarynode(paraarray[1]).left; + { do not release the unused unary minus node, it is kept and release together with the other nodes, + only no code is generated for it } + negproduct:=not(negproduct); + end; + + if paraarray[2].nodetype=unaryminusn then + begin + paraarray[2]:=tunarynode(paraarray[2]).left; + { do not release the unused unary minus node, it is kept and release together with the other nodes, + only no code is generated for it } + negproduct:=not(negproduct); + end; + for i:=1 to 3 do + secondpass(paraarray[i]); + + { no memory operand is allowed } + for i:=1 to 3 do + begin + if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then + hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true); + end; + + location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size); + location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size); + + hlcg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,paraarray[3].resultdef,resultdef, + paraarray[3].location.register,location.register); + + ai:=taicpu.op_reg_reg_reg(op[negproduct], + location.register,paraarray[1].location.register,paraarray[2].location.register); + ai.oppostfix:=PF_S; + current_asmdata.CurrAsmList.concat(ai); + + cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList); + end + else + internalerror(2020112401); + end; + begin cinlinenode:=tcpuinlinenode; diff --git a/tests/test/tfma1.inc b/tests/test/tfma1.inc index 716f7305d5..a214d78b88 100644 --- a/tests/test/tfma1.inc +++ b/tests/test/tfma1.inc @@ -241,6 +241,7 @@ procedure testsingle; halt(1); end; +{$ifndef NODOUBLE} procedure testdouble; var @@ -480,3 +481,5 @@ procedure testdouble; if l0<>-10.0 then halt(1); end; + +{$endif NODOUBLE} diff --git a/tests/test/tfma1xtensa.pp b/tests/test/tfma1xtensa.pp new file mode 100644 index 0000000000..e02f155228 --- /dev/null +++ b/tests/test/tfma1xtensa.pp @@ -0,0 +1,30 @@ +{ %CPU=xtensa } + +{$define NODOUBLE} + +{$i tfma1.inc} + +begin + { + d1:=2; + d2:=3; + d3:=4; + d0:=FMADouble(d1,d2,d3); + writeln(d0); + if d0<>10.0 then + halt(1); + } + + s1:=2; + s2:=3; + s3:=4; + s0:=FMASingle(s1,s2,s3); + writeln(s0); + if s0<>10.0 then + halt(1); + + testsingle; + // testdouble; + + writeln('ok'); +end.