n68kset.pas 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. {
  2. Copyright (c) 2016 by the Free Pascal development team
  3. Generate m68k assembler for in set/case labels
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit n68kset;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. symtype,
  23. cgbase,cpuinfo,cpubase,
  24. node,nset,ncgset;
  25. type
  26. tcpucasenode = class(tcgcasenode)
  27. procedure genlinearlist(hp : pcaselabel); override;
  28. end;
  29. implementation
  30. uses
  31. systems,globals,
  32. cutils,verbose,
  33. symdef,paramgr,
  34. aasmtai,aasmdata,
  35. nflw,constexp,
  36. cgutils,cgobj,hlcgobj,
  37. defutil,cgcpu;
  38. procedure tcpucasenode.genlinearlist(hp : pcaselabel);
  39. var
  40. first : boolean;
  41. last : TConstExprInt;
  42. scratch_reg: tregister;
  43. newsize: tcgsize;
  44. newdef: tdef;
  45. procedure genitem(t : pcaselabel);
  46. begin
  47. if assigned(t^.less) then
  48. genitem(t^.less);
  49. { do we need to test the first value? }
  50. if first and (t^._low>get_min_value(left.resultdef)) then
  51. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_lt,tcgint(t^._low.svalue),hregister,elselabel);
  52. if t^._low=t^._high then
  53. begin
  54. if t^._low-last=0 then
  55. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,OC_EQ,0,hregister,blocklabel(t^.blockid))
  56. else
  57. begin
  58. hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue-last.svalue), hregister);
  59. tcg68k(cg).a_jmp_cond(current_asmdata.CurrAsmList,OC_EQ,blocklabel(t^.blockid));
  60. end;
  61. last:=t^._low;
  62. end
  63. else
  64. begin
  65. { it begins with the smallest label, if the value }
  66. { is even smaller then jump immediately to the }
  67. { ELSE-label }
  68. if first then
  69. begin
  70. { have we to ajust the first value ? }
  71. if (t^._low>get_min_value(left.resultdef)) or (get_min_value(left.resultdef)<>0) then
  72. hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue), hregister);
  73. end
  74. else
  75. begin
  76. { if there is no unused label between the last and the }
  77. { present label then the lower limit can be checked }
  78. { immediately. else check the range in between: }
  79. hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._low.svalue-last.svalue), hregister);
  80. tcg68k(cg).a_jmp_cond(current_asmdata.CurrAsmList, jmp_lt, elselabel);
  81. end;
  82. hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, tcgint(t^._high.svalue-t^._low.svalue), hregister);
  83. tcg68k(cg).a_jmp_cond(current_asmdata.CurrAsmList, jmp_le, blocklabel(t^.blockid));
  84. last:=t^._high;
  85. end;
  86. first:=false;
  87. if assigned(t^.greater) then
  88. genitem(t^.greater);
  89. end;
  90. begin
  91. { do we need to generate cmps? }
  92. if (with_sign and (min_label<0)) then
  93. genlinearcmplist(hp)
  94. else
  95. begin
  96. { sign/zero extend the value to a full register before starting to
  97. subtract values, so that on platforms that don't have
  98. subregisters of the same size as the value we don't generate
  99. sign/zero-extensions after every subtraction
  100. make newsize always signed, since we only do this if the size in
  101. bytes of the register is larger than the original opsize, so
  102. the value can always be represented by a larger signed type }
  103. newsize:=tcgsize2signed[reg_cgsize(hregister)];
  104. if tcgsize2size[newsize]>opsize.size then
  105. begin
  106. newdef:=cgsize_orddef(newsize);
  107. scratch_reg:=hlcg.getintregister(current_asmdata.CurrAsmList,newdef);
  108. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opsize,newdef,hregister,scratch_reg);
  109. hregister:=scratch_reg;
  110. opsize:=newdef;
  111. end;
  112. last:=0;
  113. first:=true;
  114. genitem(hp);
  115. hlcg.a_jmp_always(current_asmdata.CurrAsmList,elselabel);
  116. end;
  117. end;
  118. begin
  119. ccasenode:=tcpucasenode;
  120. end.