Browse Source

Fix optimizations of Thumb-2 code
Fix problem with loading of condition operand for IT instructions
Properly split IT blocks when register allocator tries to spill inside a block.

git-svn-id: branches/laksen/arm-embedded@22582 -

Jeppe Johansen 12 years ago
parent
commit
b788ba660d
3 changed files with 135 additions and 10 deletions
  1. 2 2
      compiler/arm/aasmcpu.pas
  2. 12 8
      compiler/arm/aoptcpu.pas
  3. 121 0
      compiler/arm/rgcpu.pas

+ 2 - 2
compiler/arm/aasmcpu.pas

@@ -478,8 +478,8 @@ implementation
     constructor taicpu.op_cond(op: tasmop; cond: tasmcond);
     constructor taicpu.op_cond(op: tasmop; cond: tasmcond);
       begin
       begin
         inherited create(op);
         inherited create(op);
-        ops:=0;
-        condition := cond;
+        ops:=1;
+        loadconditioncode(0, cond);
       end;
       end;
 
 
     constructor taicpu.op_modeflags(op: tasmop; flags: tcpumodeflags);
     constructor taicpu.op_modeflags(op: tasmop; flags: tcpumodeflags);

+ 12 - 8
compiler/arm/aoptcpu.pas

@@ -79,6 +79,7 @@ Implementation
       result:=
       result:=
         (p.typ=ait_instruction) and
         (p.typ=ait_instruction) and
         (taicpu(p).condition=C_None) and
         (taicpu(p).condition=C_None) and
+        ((taicpu(p).opcode<A_IT) or (taicpu(p).opcode>A_ITTTT)) and
         (taicpu(p).opcode<>A_PLD) and
         (taicpu(p).opcode<>A_PLD) and
         ((taicpu(p).opcode<>A_BLX) or
         ((taicpu(p).opcode<>A_BLX) or
          (taicpu(p).oper[0]^.typ=top_reg));
          (taicpu(p).oper[0]^.typ=top_reg));
@@ -265,6 +266,15 @@ Implementation
       end;
       end;
   end;
   end;
 
 
+  function isValidConstLoadStoreOffset(const aoffset: longint; const pf: TOpPostfix) : boolean;
+    begin
+      if current_settings.cputype in cpu_thumb2 then
+        result := (aoffset<4096) and (aoffset>-256)
+      else
+        result := ((pf in [PF_None,PF_B]) and
+                   (abs(aoffset)<4096)) or
+                  (abs(aoffset)<256);
+    end;
 
 
   function TCpuAsmOptimizer.RegUsedAfterInstruction(reg: Tregister; p: tai;
   function TCpuAsmOptimizer.RegUsedAfterInstruction(reg: Tregister; p: tai;
     var AllUsedRegs: TAllUsedRegs): Boolean;
     var AllUsedRegs: TAllUsedRegs): Boolean;
@@ -1094,16 +1104,10 @@ Implementation
                           { new offset must be valid: either in the range of 8 or 12 bit, depend on the
                           { new offset must be valid: either in the range of 8 or 12 bit, depend on the
                             ldr postfix }
                             ldr postfix }
                           (((taicpu(p).opcode=A_ADD) and
                           (((taicpu(p).opcode=A_ADD) and
-                            (((taicpu(hp1).oppostfix in [PF_None,PF_B]) and
-                              (abs(taicpu(hp1).oper[1]^.ref^.offset+taicpu(p).oper[2]^.val)<4096)) or
-                             (abs(taicpu(hp1).oper[1]^.ref^.offset+taicpu(p).oper[2]^.val)<256)
-                            )
+                           isValidConstLoadStoreOffset(taicpu(hp1).oper[1]^.ref^.offset+taicpu(p).oper[2]^.val, taicpu(hp1).oppostfix)
                            ) or
                            ) or
                            ((taicpu(p).opcode=A_SUB) and
                            ((taicpu(p).opcode=A_SUB) and
-                             (((taicpu(hp1).oppostfix in [PF_None,PF_B]) and
-                               (abs(taicpu(hp1).oper[1]^.ref^.offset-taicpu(p).oper[2]^.val)<4096)) or
-                              (abs(taicpu(hp1).oper[1]^.ref^.offset-taicpu(p).oper[2]^.val)<256)
-                             )
+                            isValidConstLoadStoreOffset(taicpu(hp1).oper[1]^.ref^.offset-taicpu(p).oper[2]^.val, taicpu(hp1).oppostfix)
                            )
                            )
                           ) do
                           ) do
                           begin
                           begin

+ 121 - 0
compiler/arm/rgcpu.pas

@@ -45,6 +45,9 @@ unit rgcpu;
        end;
        end;
 
 
        trgcputhumb2 = class(trgobj)
        trgcputhumb2 = class(trgobj)
+       private
+         procedure SplitITBlock(list:TAsmList;pos:tai);
+       public
          procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
          procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
          procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
          procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
        end;
        end;
@@ -245,6 +248,100 @@ unit rgcpu;
           result:=getsubreg(r);
           result:=getsubreg(r);
       end;
       end;
 
 
+    function IsIT(op: TAsmOp) : boolean;
+      begin
+        case op of
+          A_IT,
+          A_ITE, A_ITT,
+          A_ITEE, A_ITTE, A_ITET, A_ITTT,
+          A_ITEEE, A_ITTEE, A_ITETE, A_ITTTE,
+          A_ITEET, A_ITTET, A_ITETT, A_ITTTT:
+            result:=true;
+        else
+          result:=false;
+        end;
+      end;
+
+    function GetITLevels(op: TAsmOp) : longint;
+      begin
+        case op of
+          A_IT:
+            result:=1;
+          A_ITE, A_ITT:
+            result:=2;
+          A_ITEE, A_ITTE, A_ITET, A_ITTT:
+            result:=3;
+          A_ITEEE, A_ITTEE, A_ITETE, A_ITTTE,
+          A_ITEET, A_ITTET, A_ITETT, A_ITTTT:
+            result:=4;
+        else
+          result:=0;
+        end;
+      end;
+
+    function GetITRemainderOp(originalOp:TAsmOp;remLevels:longint;var newOp: TAsmOp;var NeedsCondSwap:boolean) : TAsmOp;
+      const
+        remOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
+          (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),
+          (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),
+          (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));
+        newOps : array[1..3] of array[A_ITE..A_ITTTT] of TAsmOp = (
+          (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),
+          (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),
+          (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));
+        needsSwap: array[1..3] of array[A_ITE..A_ITTTT] of Boolean = (
+          (true ,false,     true ,true ,false,false,        true ,true ,true ,true ,false,false,false,false),
+          (false,false,     true ,false,true ,false,        true ,true ,false,false,true ,true ,false,false),
+          (false,false,     false,false,false,false,        true ,false,true ,false,true ,false,true ,false));
+      begin
+        result:=remOps[remLevels][originalOp];
+        newOp:=newOps[remLevels][originalOp];
+        NeedsCondSwap:=needsSwap[remLevels][originalOp];
+      end;
+
+    procedure trgcputhumb2.SplitITBlock(list: TAsmList; pos: tai);
+      var
+        hp : tai;
+        level,itLevel : LongInt;
+        remOp,newOp : TAsmOp;
+        needsSwap : boolean;
+      begin
+        hp:=pos;
+        level := 0;
+        while assigned(hp) do
+          begin
+            if IsIT(taicpu(hp).opcode) then
+              break
+            else if hp.typ=ait_instruction then
+              inc(level);
+
+            hp:=tai(hp.Previous);
+          end;
+
+        if not assigned(hp) then
+          internalerror(2012100801); // We are supposed to have found the ITxxx instruction here
+
+        if (hp.typ<>ait_instruction) or
+          (not IsIT(taicpu(hp).opcode)) then
+          internalerror(2012100802); // Sanity check
+
+        itLevel := GetITLevels(taicpu(hp).opcode);
+        if level=itLevel then
+          exit; // pos was the last instruction in the IT block anyway
+
+        remOp:=GetITRemainderOp(taicpu(hp).opcode,itLevel-level,newOp,needsSwap);
+
+        if (remOp=A_NONE) or
+          (newOp=A_NONE) then
+          Internalerror(2012100803);
+
+        taicpu(hp).opcode:=newOp;
+
+        if needsSwap then
+          list.InsertAfter(taicpu.op_cond(remOp,inverse_cond(taicpu(hp).oper[0]^.cc)), pos)
+        else
+          list.InsertAfter(taicpu.op_cond(remOp,taicpu(hp).oper[0]^.cc), pos);
+      end;
 
 
     procedure trgcputhumb2.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
     procedure trgcputhumb2.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
       var
       var
@@ -267,6 +364,18 @@ unit rgcpu;
           (taicpu(pos).oper[1]^.reg=NR_PC) then
           (taicpu(pos).oper[1]^.reg=NR_PC) then
           pos:=tai(pos.previous);
           pos:=tai(pos.previous);
 
 
+        if (pos.typ=ait_instruction) and
+          (taicpu(pos).condition<>C_None) and
+          (taicpu(pos).opcode<>A_B) then
+          SplitITBlock(list, pos)
+        else if (pos.typ=ait_instruction) and
+          IsIT(taicpu(pos).opcode) then
+          begin
+            if not assigned(pos.Previous) then
+              list.InsertBefore(tai_comment.Create('Dummy'), pos);
+            pos:=tai(pos.Previous);
+          end;
+
         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
           begin
           begin
             helplist:=TAsmList.create;
             helplist:=TAsmList.create;
@@ -313,6 +422,18 @@ unit rgcpu;
         l : tasmlabel;
         l : tasmlabel;
         hreg : tregister;
         hreg : tregister;
       begin
       begin
+        if (pos.typ=ait_instruction) and
+          (taicpu(pos).condition<>C_None) and
+          (taicpu(pos).opcode<>A_B) then
+          SplitITBlock(list, pos)
+        else if (pos.typ=ait_instruction) and
+          IsIT(taicpu(pos).opcode) then
+          begin
+            if not assigned(pos.Previous) then
+              list.InsertBefore(tai_comment.Create('Dummy'), pos);
+            pos:=tai(pos.Previous);
+          end;
+
         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
         if (spilltemp.offset>4095) or (spilltemp.offset<-255) then
           begin
           begin
             helplist:=TAsmList.create;
             helplist:=TAsmList.create;