diff --git a/.gitattributes b/.gitattributes index 6cd223603b..a87b01f92a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -377,6 +377,7 @@ compiler/m68k/n68kcnv.pas svneol=native#text/plain compiler/m68k/n68kinl.pas svneol=native#text/plain compiler/m68k/n68kmat.pas svneol=native#text/plain compiler/m68k/n68kmem.pas svneol=native#text/plain +compiler/m68k/n68kset.pas svneol=native#text/plain compiler/m68k/r68kbss.inc svneol=native#text/plain compiler/m68k/r68kcon.inc svneol=native#text/plain compiler/m68k/r68kgas.inc svneol=native#text/plain diff --git a/compiler/m68k/cpunode.pas b/compiler/m68k/cpunode.pas index d956bc9826..489da54e16 100644 --- a/compiler/m68k/cpunode.pas +++ b/compiler/m68k/cpunode.pas @@ -39,7 +39,7 @@ unit cpunode; // nppccon, // nppcflw, n68kmem, -// nppcset, + n68kset, n68kinl, // nppcopt, { this not really a node } diff --git a/compiler/m68k/n68kset.pas b/compiler/m68k/n68kset.pas new file mode 100644 index 0000000000..8df6712ff0 --- /dev/null +++ b/compiler/m68k/n68kset.pas @@ -0,0 +1,138 @@ +{ + Copyright (c) 2016 by the Free Pascal development team + + Generate m68k assembler for in set/case labels + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit n68kset; + +{$i fpcdefs.inc} + +interface + + uses + globtype, + symtype, + cgbase,cpuinfo,cpubase, + node,nset,ncgset; + + type + tcpucasenode = class(tcgcasenode) + procedure genlinearlist(hp : pcaselabel); override; + end; + +implementation + + uses + systems,globals, + cutils,verbose, + symdef,paramgr, + aasmtai,aasmdata, + nflw,constexp, + cgutils,cgobj,hlcgobj, + defutil; + + procedure tcpucasenode.genlinearlist(hp : pcaselabel); + + var + first : boolean; + last : TConstExprInt; + scratch_reg: tregister; + newsize: tcgsize; + newdef: tdef; + + procedure genitem(t : pcaselabel); + + begin + if assigned(t^.less) then + genitem(t^.less); + { do we need to test the first value? } + if first and (t^._low>get_min_value(left.resultdef)) then + hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_lt,tcgint(t^._low.svalue),hregister,elselabel); + if t^._low=t^._high then + begin + if t^._low-last=0 then + hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,OC_EQ,0,hregister,blocklabel(t^.blockid)) + else + begin + hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue-last.svalue), hregister); + hlcg.a_jmp_flags(current_asmdata.CurrAsmList,F_E,blocklabel(t^.blockid)); + end; + last:=t^._low; + end + else + begin + { it begins with the smallest label, if the value } + { is even smaller then jump immediately to the } + { ELSE-label } + if first then + begin + { have we to ajust the first value ? } + if (t^._low>get_min_value(left.resultdef)) or (get_min_value(left.resultdef)<>0) then + hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue), hregister); + end + else + begin + { if there is no unused label between the last and the } + { present label then the lower limit can be checked } + { immediately. else check the range in between: } + hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue-last.svalue), hregister); + hlcg.a_jmp_flags(current_asmdata.CurrAsmList,F_L,elselabel); + end; + hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._high.svalue-t^._low.svalue), hregister); + hlcg.a_jmp_flags(current_asmdata.CurrAsmList,F_LE,blocklabel(t^.blockid)); + last:=t^._high; + end; + first:=false; + if assigned(t^.greater) then + genitem(t^.greater); + end; + + begin + { do we need to generate cmps? } + if (with_sign and (min_label<0)) then + genlinearcmplist(hp) + else + begin + { sign/zero extend the value to a full register before starting to + subtract values, so that on platforms that don't have + subregisters of the same size as the value we don't generate + sign/zero-extensions after every subtraction + + make newsize always signed, since we only do this if the size in + bytes of the register is larger than the original opsize, so + the value can always be represented by a larger signed type } + newsize:=tcgsize2signed[reg_cgsize(hregister)]; + if tcgsize2size[newsize]>opsize.size then + begin + newdef:=cgsize_orddef(newsize); + scratch_reg:=hlcg.getintregister(current_asmdata.CurrAsmList,newdef); + hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opsize,newdef,hregister,scratch_reg); + hregister:=scratch_reg; + opsize:=newdef; + end; + last:=0; + first:=true; + genitem(hp); + hlcg.a_jmp_always(current_asmdata.CurrAsmList,elselabel); + end; + end; + +begin + ccasenode:=tcpucasenode; +end.