1 {
2     Copyright (c) 1998-2008 by Florian Klaempfl
3 
4     Generates AVR assembler for math nodes
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 unit navrmat;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       node,nmat,ncgmat;
30 
31     type
32       tavrnotnode = class(tcgnotnode)
33         procedure second_boolean;override;
34       end;
35 
36       tavrshlshrnode = class(tcgshlshrnode)
37         procedure second_integer;override;
38       end;
39 
40 implementation
41 
42     uses
43       globtype,systems,
44       cutils,verbose,globals,constexp,
45       symtype,symdef,
46       aasmbase,aasmcpu,aasmtai,aasmdata,
47       defutil,
48       cgbase,cgobj,hlcgobj,cgutils,
49       pass_2,procinfo,
50       ncon,
51       cpubase,
52       ncgutil,cgcpu;
53 
54 {*****************************************************************************
55                                TAVRNOTNODE
56 *****************************************************************************}
57 
58     procedure tavrnotnode.second_boolean;
59       var
60         tmpreg,lreg : tregister;
61         i : longint;
62         falselabel,truelabel,skiplabel: TAsmLabel;
63       begin
64         if not handle_locjump then
65           begin
66             secondpass(left);
67             { short code? }
68             if (left.location.loc in [LOC_SUBSETREG,LOC_CSUBSETREG]) and
69               (left.location.sreg.bitlen=1) then
70               begin
71                 current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_SBRC,left.location.sreg.subsetreg,left.location.sreg.startbit));
72                 current_asmdata.getjumplabel(truelabel);
73                 current_asmdata.getjumplabel(falselabel);
74                 { sbrc does a jump without an explicit label,
75                   if we do not insert skiplabel here and increase its reference count, the optimizer removes the whole true block altogether }
76                 current_asmdata.getjumplabel(skiplabel);
77                 skiplabel.increfs;
78                 location_reset_jump(location,truelabel,falselabel);
79                 cg.a_jmp_always(current_asmdata.CurrAsmList,falselabel);
80                 cg.a_label(current_asmdata.CurrAsmList,skiplabel);
81                 cg.a_jmp_always(current_asmdata.CurrAsmList,truelabel);
82               end
83             else if (left.location.loc in [LOC_SUBSETREF,LOC_CSUBSETREF]) and
84               (left.location.sref.bitlen=1) and (left.location.sref.bitindexreg=NR_NO) then
85               begin
86                 tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_8);
87                 hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,u8inttype,osuinttype,left.location.sref.ref,tmpreg);
88                 current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_SBRC,tmpreg,left.location.sref.startbit));
89                 current_asmdata.getjumplabel(truelabel);
90                 current_asmdata.getjumplabel(falselabel);
91                 { sbrc does a jump without an explicit label,
92                   if we do not insert skiplabel here and increase its reference count, the optimizer removes the whole true block altogether }
93                 current_asmdata.getjumplabel(skiplabel);
94                 skiplabel.increfs;
95                 location_reset_jump(location,truelabel,falselabel);
96                 cg.a_jmp_always(current_asmdata.CurrAsmList,falselabel);
97                 cg.a_label(current_asmdata.CurrAsmList,skiplabel);
98                 cg.a_jmp_always(current_asmdata.CurrAsmList,truelabel);
99               end
100             else
101               case left.location.loc of
102                  LOC_FLAGS :
103                    begin
104                      location_copy(location,left.location);
105                      inverse_flags(location.resflags);
106                    end;
107                  LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF,
108                  LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE :
109                    begin
110                      hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
111                      current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CPI,left.location.register,0));
112 
113                      tmpreg:=left.location.register;
114                      for i:=2 to tcgsize2size[left.location.size] do
115                        begin
116                          if i=5 then
117                            tmpreg:=left.location.registerhi
118                          else
119                            tmpreg:=cg.GetNextReg(tmpreg);
120                          current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CPC,NR_R1,tmpreg));
121                        end;
122                      location_reset(location,LOC_FLAGS,OS_NO);
123                      location.resflags:=F_EQ;
124                   end;
125                  else
126                    internalerror(2003042401);
127                end;
128           end;
129       end;
130 
131 
132     procedure tavrshlshrnode.second_integer;
133       var
134          op : topcg;
135          opdef: tdef;
136          hcountreg : tregister;
137          opsize : tcgsize;
138          shiftval : longint;
139       begin
140         { determine operator }
141         case nodetype of
142           shln: op:=OP_SHL;
143           shrn: op:=OP_SHR;
144           else
145             internalerror(2013120102);
146         end;
147         opsize:=left.location.size;
148         opdef:=left.resultdef;
149 
150         if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or
151           { location_force_reg can be also used to change the size of a register }
152           (left.location.size<>opsize) then
153           hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,true);
154         location_reset(location,LOC_REGISTER,opsize);
155         location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
156 
157         { shifting by a constant directly coded: }
158         if (right.nodetype=ordconstn) then
159           begin
160              { shl/shr must "wrap around", so use ... and 31 }
161              { In TP, "byte/word shl 16 = 0", so no "and 15" in case of
162                a 16 bit ALU }
163              if tcgsize2size[opsize]<=4 then
164                shiftval:=tordconstnode(right).value.uvalue and 31
165              else
166                shiftval:=tordconstnode(right).value.uvalue and 63;
167              hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,op,opdef,
168                shiftval,left.location.register,location.register);
169           end
170         else
171           begin
172              { load right operators in a register - this
173                is done since most target cpu which will use this
174                node do not support a shift count in a mem. location (cec)
175              }
176              hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,sinttype,true);
177              hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,right.location.register,left.location.register,location.register);
178           end;
179         { shl/shr nodes return the same type as left, which can be different
180           from opdef }
181         if opdef<>resultdef then
182           begin
183             hcountreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
184             hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opdef,resultdef,location.register,hcountreg);
185             location.register:=hcountreg;
186           end;
187       end;
188 
189 begin
190   cnotnode:=tavrnotnode;
191   cshlshrnode:=tavrshlshrnode;
192 end.
193