1 {
2     Copyright (c) 1998-2003 by Florian Klaempfl
3 
4     This unit implements the arm specific class for the register
5     allocator
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  ****************************************************************************
22 }
23 
24 unit rgcpu;
25 
26 {$i fpcdefs.inc}
27 
28   interface
29 
30      uses
31        aasmbase,aasmtai,aasmsym,aasmdata,aasmcpu,
32        cgbase,cgutils,
33        cpubase,
34        {$ifdef DEBUG_SPILLING}
35        cutils,
36        {$endif}
37        rgobj;
38 
39      type
40        trgcpu = class(trgobj)
41        private
42          procedure spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
43        public
44          procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
45          procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
do_spill_replacenull46          function do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym;
47            orgreg : tsuperregister;const spilltemp : treference) : boolean;override;
48          procedure add_constraints(reg:tregister);override;
get_spill_subregnull49          function  get_spill_subreg(r:tregister) : tsubregister;override;
50        end;
51 
52        trgcputhumb2 = class(trgobj)
53        private
54          procedure SplitITBlock(list:TAsmList;pos:tai);
55        public
56          procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
57          procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
58        end;
59 
60        trgintcputhumb2 = class(trgcputhumb2)
61          procedure add_cpu_interferences(p : tai);override;
62        end;
63 
64        trgintcpu = class(trgcpu)
65          procedure add_cpu_interferences(p : tai);override;
66        end;
67 
68        trgcputhumb = class(trgcpu)
69        end;
70 
71        trgintcputhumb = class(trgcputhumb)
72          procedure add_cpu_interferences(p: tai);override;
73        end;
74 
75 
76   implementation
77 
78     uses
79       verbose,globtype,globals,cpuinfo,
80       cgobj,
81       procinfo;
82 
83     procedure trgintcputhumb2.add_cpu_interferences(p: tai);
84       var
85         r : tregister;
86         hr : longint;
87       begin
88         if p.typ=ait_instruction then
89           begin
90             case taicpu(p).opcode of
91               A_CBNZ,
92               A_CBZ:
93                 begin
94                   for hr := RS_R8 to RS_R15 do
95                     add_edge(getsupreg(taicpu(p).oper[0]^.reg), hr);
96                 end;
97               A_ADD,
98               A_SUB,
99               A_AND,
100               A_BIC,
101               A_EOR:
102                 begin
103                   if taicpu(p).ops = 3 then
104                     begin
105                       if (taicpu(p).oper[0]^.typ = top_reg) and
106                          (taicpu(p).oper[1]^.typ = top_reg) and
107                          (taicpu(p).oper[2]^.typ in [top_reg, top_shifterop]) then
108                         begin
109                           { if d == 13 || (d == 15 && S == ‚Äò0‚Äô) || n == 15 || m IN [13,15] then UNPREDICTABLE; }
110                           add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R13);
111                           if taicpu(p).oppostfix <> PF_S then
112                             add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R15);
113 
114                           add_edge(getsupreg(taicpu(p).oper[1]^.reg), RS_R15);
115 
116                           if (taicpu(p).oper[2]^.typ = top_shifterop) and
117                              (taicpu(p).oper[2]^.shifterop^.rs <> NR_NO) then
118                             begin
119                               add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R13);
120                               add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R15);
121                             end
122                           else if (taicpu(p).oper[2]^.typ = top_reg) then
123                             begin
124                               add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R13);
125                               add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R15);
126                             end;
127                         end;
128                     end;
129                 end;
130               A_MLA,
131               A_MLS,
132               A_MUL:
133                 begin
134                   if (current_settings.cputype<cpu_armv6) and (taicpu(p).opcode<>A_MLS) then
135                     add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
136                    add_edge(getsupreg(taicpu(p).oper[0]^.reg),RS_R13);
137                    add_edge(getsupreg(taicpu(p).oper[0]^.reg),RS_R15);
138                    add_edge(getsupreg(taicpu(p).oper[1]^.reg),RS_R13);
139                    add_edge(getsupreg(taicpu(p).oper[1]^.reg),RS_R15);
140                    add_edge(getsupreg(taicpu(p).oper[2]^.reg),RS_R13);
141                    add_edge(getsupreg(taicpu(p).oper[2]^.reg),RS_R15);
142                    if taicpu(p).opcode<>A_MUL then
143                      begin
144                        add_edge(getsupreg(taicpu(p).oper[3]^.reg),RS_R13);
145                        add_edge(getsupreg(taicpu(p).oper[3]^.reg),RS_R15);
146                      end;
147                 end;
148               A_LDRB,
149               A_STRB,
150               A_STR,
151               A_LDR,
152               A_LDRH,
153               A_STRH,
154               A_LDRSB,
155               A_LDRSH,
156               A_LDRD,
157               A_STRD:
158                 { don't mix up the framepointer and stackpointer with pre/post indexed operations }
159                 if (taicpu(p).oper[1]^.typ=top_ref) and
160                   (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
161                   begin
162                     add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
163                     { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
164                     {        while compiling the compiler. }
165                     r:=NR_STACK_POINTER_REG;
166                     if current_procinfo.framepointer<>r then
167                       add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
168                   end;
169             end;
170           end;
171       end;
172 
173     procedure trgcpu.spilling_create_load_store(list: TAsmList; pos: tai; const spilltemp:treference;tempreg:tregister; is_store: boolean);
174       var
175         tmpref : treference;
176         helplist : TAsmList;
177         hreg : tregister;
178         immshift: byte;
179         a: aint;
180     begin
181       helplist:=TAsmList.create;
182 
183       { load consts entry }
184       if getregtype(tempreg)=R_INTREGISTER then
185         hreg:=getregisterinline(helplist,[R_SUBWHOLE])
186       else
187         hreg:=cg.getintregister(helplist,OS_ADDR);
188 
189       { Lets remove the bits we can fold in later and check if the result can be easily with an add or sub }
190       a:=abs(spilltemp.offset);
191       if GenerateThumbCode or (getregtype(tempreg)=R_MMREGISTER) then
192         begin
193           {$ifdef DEBUG_SPILLING}
194           helplist.concat(tai_comment.create(strpnew('Spilling: Use a_load_const_reg to fix spill offset')));
195           {$endif}
196           cg.a_load_const_reg(helplist,OS_ADDR,spilltemp.offset,hreg);
197           cg.a_op_reg_reg(helplist,OP_ADD,OS_ADDR,current_procinfo.framepointer,hreg);
198           reference_reset_base(tmpref,hreg,0,spilltemp.temppos,sizeof(aint),[]);
199         end
200       else if is_shifter_const(a and not($FFF), immshift) then
201         if spilltemp.offset > 0 then
202           begin
203             {$ifdef DEBUG_SPILLING}
204             helplist.concat(tai_comment.create(strpnew('Spilling: Use ADD to fix spill offset')));
205             {$endif}
206             helplist.concat(taicpu.op_reg_reg_const(A_ADD, hreg, current_procinfo.framepointer,
207                                                       a and not($FFF)));
208             reference_reset_base(tmpref, hreg, a and $FFF, spilltemp.temppos, sizeof(aint),[]);
209           end
210         else
211           begin
212             {$ifdef DEBUG_SPILLING}
213             helplist.concat(tai_comment.create(strpnew('Spilling: Use SUB to fix spill offset')));
214             {$endif}
215             helplist.concat(taicpu.op_reg_reg_const(A_SUB, hreg, current_procinfo.framepointer,
216                                                       a and not($FFF)));
217             reference_reset_base(tmpref, hreg, -(a and $FFF), spilltemp.temppos, sizeof(aint),[]);
218           end
219       else
220         begin
221           {$ifdef DEBUG_SPILLING}
222           helplist.concat(tai_comment.create(strpnew('Spilling: Use a_load_const_reg to fix spill offset')));
223           {$endif}
224           cg.a_load_const_reg(helplist,OS_ADDR,spilltemp.offset,hreg);
225           reference_reset_base(tmpref,current_procinfo.framepointer,0,spilltemp.temppos,sizeof(aint),[]);
226           tmpref.index:=hreg;
227         end;
228 
229       if spilltemp.index<>NR_NO then
230         internalerror(200401263);
231 
232       if is_store then
233         helplist.concat(spilling_create_store(tempreg,tmpref))
234       else
235         helplist.concat(spilling_create_load(tmpref,tempreg));
236 
237       if getregtype(tempreg)=R_INTREGISTER then
238         ungetregisterinline(helplist,hreg);
239 
240       list.insertlistafter(pos,helplist);
241       helplist.free;
242     end;
243 
244 
fix_spilling_offsetnull245    function fix_spilling_offset(regtype : TRegisterType;offset : ASizeInt) : boolean;
246      begin
247        result:=(abs(offset)>4095) or
248          ((regtype=R_MMREGISTER) and (abs(offset)>1020)) or
249           ((GenerateThumbCode) and ((offset<0) or (offset>1020)));
250      end;
251 
252 
253     procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
254       begin
255         { don't load spilled register between
256           mov lr,pc
257           mov pc,r4
258           but before the mov lr,pc
259         }
260         if assigned(pos.previous) and
261           (pos.typ=ait_instruction) and
262           (taicpu(pos).opcode=A_MOV) and
263           (taicpu(pos).oper[0]^.typ=top_reg) and
264           (taicpu(pos).oper[0]^.reg=NR_R14) and
265           (taicpu(pos).oper[1]^.typ=top_reg) and
266           (taicpu(pos).oper[1]^.reg=NR_PC) then
267           pos:=tai(pos.previous);
268 
269         if fix_spilling_offset(getregtype(tempreg),spilltemp.offset) then
270           spilling_create_load_store(list, pos, spilltemp, tempreg, false)
271         else
272           inherited;
273       end;
274 
275 
276     procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
277       begin
278         if fix_spilling_offset(getregtype(tempreg),spilltemp.offset) then
279           spilling_create_load_store(list, pos, spilltemp, tempreg, true)
280         else
281           inherited;
282       end;
283 
284 
trgcpu.do_spill_replacenull285     function trgcpu.do_spill_replace(list:TAsmList;instr:tai_cpu_abstract_sym;orgreg:tsuperregister;const spilltemp:treference):boolean;
286       begin
287         result:=false;
288         if abs(spilltemp.offset)>4095 then
289           exit;
290 
291         { ldr can't set the flags }
292         if taicpu(instr).oppostfix=PF_S then
293           exit;
294 
295         if GenerateThumbCode and
296           (abs(spilltemp.offset)>1020) then
297           exit;
298 
299         { Replace 'mov  dst,orgreg' with 'ldr  dst,spilltemp'
300           and     'mov  orgreg,src' with 'str  dst,spilltemp' }
301         with instr do
302           begin
303             if (opcode=A_MOV) and (ops=2) and (oper[1]^.typ=top_reg) and (oper[0]^.typ=top_reg) then
304               begin
305                 if (getregtype(oper[0]^.reg)=regtype) and
306                    (get_alias(getsupreg(oper[0]^.reg))=orgreg) and
307                    (get_alias(getsupreg(oper[1]^.reg))<>orgreg) then
308                   begin
309                     { do not replace if we're on Thumb, ldr/str cannot be used with rX>r7 }
310                     if GenerateThumbCode and
311                        (getsupreg(oper[1]^.reg)>RS_R7) then
312                        exit;
313 
314                     { str expects the register in oper[0] }
315                     instr.loadreg(0,oper[1]^.reg);
316                     instr.loadref(1,spilltemp);
317                     opcode:=A_STR;
318                     result:=true;
319                   end
320                 else if (getregtype(oper[1]^.reg)=regtype) and
321                    (get_alias(getsupreg(oper[1]^.reg))=orgreg) and
322                    (get_alias(getsupreg(oper[0]^.reg))<>orgreg) then
323                   begin
324                     { do not replace if we're on Thumb, ldr/str cannot be used with rX>r7 }
325                     if GenerateThumbCode and
326                        (getsupreg(oper[0]^.reg)>RS_R7) then
327                        exit;
328 
329                     instr.loadref(1,spilltemp);
330                     opcode:=A_LDR;
331                     result:=true;
332                   end;
333               end;
334           end;
335       end;
336 
337 
338     procedure trgcpu.add_constraints(reg:tregister);
339       var
340         supreg,i : Tsuperregister;
341       begin
342         case getsubreg(reg) of
343           { Let 32bit floats conflict with all double precision regs > 15
344             (since these don't have 32 bit equivalents) }
345           R_SUBFS:
346             begin
347               supreg:=getsupreg(reg);
348               for i:=RS_D16 to RS_D31 do
349                 add_edge(supreg,i);
350               { further, we cannot use the odd single registers as the register
351                 allocator cannot handle overlapping registers so far }
352               for i in [RS_S1,RS_S3,RS_S5,RS_S7,RS_S9,RS_S11,RS_S13,RS_S15,RS_S17,RS_S19,
353                 RS_S21,RS_S23,RS_S25,RS_S27,RS_S29,RS_S31] do
354                 add_edge(supreg,i);
355             end;
356         end;
357       end;
358 
359 
trgcpu.get_spill_subregnull360     function  trgcpu.get_spill_subreg(r:tregister) : tsubregister;
361       begin
362         if (getregtype(r)<>R_MMREGISTER) then
363           result:=defaultsub
364         else
365           result:=getsubreg(r);
366       end;
367 
GetITRemainderOpnull368     function GetITRemainderOp(originalOp:TAsmOp;remLevels:longint;var newOp: TAsmOp;var NeedsCondSwap:boolean) : TAsmOp;
369       const
370         remOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
371           (A_IT,A_IT,       A_IT,A_IT,A_IT,A_IT,            A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT),
372           (A_NONE,A_NONE,   A_ITT,A_ITE,A_ITE,A_ITT,        A_ITT,A_ITT,A_ITE,A_ITE,A_ITE,A_ITE,A_ITT,A_ITT),
373           (A_NONE,A_NONE,   A_NONE,A_NONE,A_NONE,A_NONE,    A_ITTT,A_ITEE,A_ITET,A_ITTE,A_ITTE,A_ITET,A_ITEE,A_ITTT));
374         newOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
375           (A_IT,A_IT,       A_ITE,A_ITT,A_ITE,A_ITT,        A_ITEE,A_ITTE,A_ITET,A_ITTT,A_ITEE,A_ITTE,A_ITET,A_ITTT),
376           (A_NONE,A_NONE,   A_IT,A_IT,A_IT,A_IT,            A_ITE,A_ITT,A_ITE,A_ITT,A_ITE,A_ITT,A_ITE,A_ITT),
377           (A_NONE,A_NONE,   A_NONE,A_NONE,A_NONE,A_NONE,    A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT,A_IT));
378         needsSwap: array[1..3] of array[A_ITE..A_ITTTT] of Boolean = (
379           (true ,false,     true ,true ,false,false,        true ,true ,true ,true ,false,false,false,false),
380           (false,false,     true ,false,true ,false,        true ,true ,false,false,true ,true ,false,false),
381           (false,false,     false,false,false,false,        true ,false,true ,false,true ,false,true ,false));
382       begin
383         result:=remOps[remLevels][originalOp];
384         newOp:=newOps[remLevels][originalOp];
385         NeedsCondSwap:=needsSwap[remLevels][originalOp];
386       end;
387 
388     procedure trgcputhumb2.SplitITBlock(list: TAsmList; pos: tai);
389       var
390         hp : tai;
391         level,itLevel : LongInt;
392         remOp,newOp : TAsmOp;
393         needsSwap : boolean;
394       begin
395         hp:=pos;
396         level := 0;
397         while assigned(hp) do
398           begin
399             if IsIT(taicpu(hp).opcode) then
400               break
401             else if hp.typ=ait_instruction then
402               inc(level);
403 
404             hp:=tai(hp.Previous);
405           end;
406 
407         if not assigned(hp) then
408           internalerror(2012100801); // We are supposed to have found the ITxxx instruction here
409 
410         if (hp.typ<>ait_instruction) or
411           (not IsIT(taicpu(hp).opcode)) then
412           internalerror(2012100802); // Sanity check
413 
414         itLevel := GetITLevels(taicpu(hp).opcode);
415         if level=itLevel then
416           exit; // pos was the last instruction in the IT block anyway
417 
418         remOp:=GetITRemainderOp(taicpu(hp).opcode,itLevel-level,newOp,needsSwap);
419 
420         if (remOp=A_NONE) or
421           (newOp=A_NONE) then
422           Internalerror(2012100803);
423 
424         taicpu(hp).opcode:=newOp;
425 
426         if needsSwap then
427           list.InsertAfter(taicpu.op_cond(remOp,inverse_cond(taicpu(hp).oper[0]^.cc)), pos)
428         else
429           list.InsertAfter(taicpu.op_cond(remOp,taicpu(hp).oper[0]^.cc), pos);
430       end;
431 
432     procedure trgcputhumb2.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister;orgsupreg:tsuperregister);
433       var
434         tmpref : treference;
435         helplist : TAsmList;
436         l : tasmlabel;
437         hreg : tregister;
438       begin
439         { don't load spilled register between
440           mov lr,pc
441           mov pc,r4
442           but before the mov lr,pc
443         }
444         if assigned(pos.previous) and
445           (pos.typ=ait_instruction) and
446           (taicpu(pos).opcode=A_MOV) and
447           (taicpu(pos).oper[0]^.typ=top_reg) and
448           (taicpu(pos).oper[0]^.reg=NR_R14) and
449           (taicpu(pos).oper[1]^.typ=top_reg) and
450           (taicpu(pos).oper[1]^.reg=NR_PC) then
451           pos:=tai(pos.previous);
452 
453         if (pos.typ=ait_instruction) and
454           (taicpu(pos).condition<>C_None) and
455           (taicpu(pos).opcode<>A_B) then
456           SplitITBlock(list, pos)
457         else if (pos.typ=ait_instruction) and
458           IsIT(taicpu(pos).opcode) then
459           begin
460             if not assigned(pos.Previous) then
461               list.InsertBefore(tai_comment.Create('Dummy'), pos);
462             pos:=tai(pos.Previous);
463           end;
464 
465         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
466           begin
467             helplist:=TAsmList.create;
468             reference_reset(tmpref,sizeof(aint),[]);
469             { create consts entry }
470             current_asmdata.getjumplabel(l);
471             cg.a_label(current_procinfo.aktlocaldata,l);
472             tmpref.symboldata:=current_procinfo.aktlocaldata.last;
473 
474             current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
475 
476             { load consts entry }
477             if getregtype(tempreg)=R_INTREGISTER then
478               hreg:=getregisterinline(helplist,[R_SUBWHOLE])
479             else
480               hreg:=cg.getintregister(helplist,OS_ADDR);
481 
482             tmpref.symbol:=l;
483             tmpref.base:=NR_R15;
484             helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
485 
486             reference_reset_base(tmpref,current_procinfo.framepointer,0,ctempposinvalid,sizeof(aint),[]);
487             tmpref.index:=hreg;
488 
489             if spilltemp.index<>NR_NO then
490               internalerror(200401263);
491 
492             helplist.concat(spilling_create_load(tmpref,tempreg));
493             if getregtype(tempreg)=R_INTREGISTER then
494               ungetregisterinline(helplist,hreg);
495 
496             list.insertlistafter(pos,helplist);
497             helplist.free;
498           end
499         else
500           inherited;
501       end;
502 
503 
504     procedure trgcputhumb2.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister;orgsupreg:tsuperregister);
505       var
506         tmpref : treference;
507         helplist : TAsmList;
508         l : tasmlabel;
509         hreg : tregister;
510       begin
511         if (pos.typ=ait_instruction) and
512           (taicpu(pos).condition<>C_None) and
513           (taicpu(pos).opcode<>A_B) then
514           SplitITBlock(list, pos)
515         else if (pos.typ=ait_instruction) and
516           IsIT(taicpu(pos).opcode) then
517           begin
518             if not assigned(pos.Previous) then
519               list.InsertBefore(tai_comment.Create('Dummy'), pos);
520             pos:=tai(pos.Previous);
521           end;
522 
523         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
524           begin
525             helplist:=TAsmList.create;
526             reference_reset(tmpref,sizeof(aint),[]);
527             { create consts entry }
528             current_asmdata.getjumplabel(l);
529             cg.a_label(current_procinfo.aktlocaldata,l);
530             tmpref.symboldata:=current_procinfo.aktlocaldata.last;
531 
532             current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(spilltemp.offset));
533 
534             { load consts entry }
535             if getregtype(tempreg)=R_INTREGISTER then
536               hreg:=getregisterinline(helplist,[R_SUBWHOLE])
537             else
538               hreg:=cg.getintregister(helplist,OS_ADDR);
539             tmpref.symbol:=l;
540             tmpref.base:=NR_R15;
541             helplist.concat(taicpu.op_reg_ref(A_LDR,hreg,tmpref));
542 
543             if spilltemp.index<>NR_NO then
544               internalerror(200401263);
545 
546             reference_reset_base(tmpref,current_procinfo.framepointer,0,ctempposinvalid,sizeof(pint),[]);
547             tmpref.index:=hreg;
548 
549             helplist.concat(spilling_create_store(tempreg,tmpref));
550 
551             if getregtype(tempreg)=R_INTREGISTER then
552               ungetregisterinline(helplist,hreg);
553 
554             list.insertlistafter(pos,helplist);
555             helplist.free;
556           end
557         else
558           inherited;
559       end;
560 
561 
562     procedure trgintcpu.add_cpu_interferences(p : tai);
563       var
564         r : tregister;
565       begin
566         if p.typ=ait_instruction then
567           begin
568             case taicpu(p).opcode of
569               A_MLA,
570               A_MUL:
571                 begin
572                   if current_settings.cputype<cpu_armv6 then
573                     add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
574                   add_edge(getsupreg(taicpu(p).oper[0]^.reg),RS_R15);
575                   add_edge(getsupreg(taicpu(p).oper[1]^.reg),RS_R15);
576                   add_edge(getsupreg(taicpu(p).oper[2]^.reg),RS_R15);
577                   if taicpu(p).opcode=A_MLA then
578                     add_edge(getsupreg(taicpu(p).oper[3]^.reg),RS_R15);
579                 end;
580               A_UMULL,
581               A_UMLAL,
582               A_SMULL,
583               A_SMLAL:
584                 begin
585                   add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[1]^.reg));
586                   if current_settings.cputype<cpu_armv6 then
587                     begin
588                       add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
589                       add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
590                     end;
591                 end;
592               A_LDRB,
593               A_STRB,
594               A_STR,
595               A_LDR,
596               A_LDRH,
597               A_STRH:
598                 { don't mix up the framepointer and stackpointer with pre/post indexed operations }
599                 if (taicpu(p).oper[1]^.typ=top_ref) and
600                   (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then
601                   begin
602                     add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(current_procinfo.framepointer));
603                     { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
604                     {        while compiling the compiler. }
605                     r:=NR_STACK_POINTER_REG;
606                     if current_procinfo.framepointer<>r then
607                       add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),getsupreg(r));
608                   end;
609             end;
610           end;
611       end;
612 
613 
614     procedure trgintcputhumb.add_cpu_interferences(p: tai);
615       var
616         r : tregister;
617         i : longint;
618       begin
619         if p.typ=ait_instruction then
620           begin
621             { prevent that the register allocator merges registers with frame/stack pointer
622               if an instruction writes to the register }
623             if (taicpu(p).ops>=1) and (taicpu(p).oper[0]^.typ=top_reg) and
624               (taicpu(p).spilling_get_operation_type(0) in [operand_write,operand_readwrite]) then
625               begin
626                 { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
627                 {        while compiling the compiler. }
628                 r:=NR_STACK_POINTER_REG;
629                 add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(r));
630                 add_edge(getsupreg(taicpu(p).oper[0]^.reg),getsupreg(current_procinfo.framepointer));
631               end;
632             if (taicpu(p).ops>=2) and (taicpu(p).oper[1]^.typ=top_reg) and
633               (taicpu(p).spilling_get_operation_type(1) in [operand_write,operand_readwrite]) then
634               begin
635                 { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
636                 {        while compiling the compiler. }
637                 r:=NR_STACK_POINTER_REG;
638                 add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(r));
639                 add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(current_procinfo.framepointer));
640               end;
641             case taicpu(p).opcode of
642               A_LDRB,
643               A_STRB,
644               A_STR,
645               A_LDR,
646               A_LDRH,
647               A_STRH,
648               A_LDRSB,
649               A_LDRSH,
650               A_LDRD,
651               A_STRD:
652                  begin
653                    { add_edge handles precoloured registers already }
654                    for i:=RS_R8 to RS_R15 do
655                      begin
656                        add_edge(getsupreg(taicpu(p).oper[1]^.ref^.base),i);
657                        add_edge(getsupreg(taicpu(p).oper[1]^.ref^.index),i);
658                        add_edge(getsupreg(taicpu(p).oper[0]^.reg),i);
659                      end;
660                  end;
661             end;
662           end;
663       end;
664 
665 end.
666