浏览代码

o patch by Jeppe Johansen to fix mantis #17472:
* generate add.w instead of add for thumb-2 in case one of the registers
is > r8
* add register interferences for the "add" instruction so the register
allocator can detect invalid instruction forms (even for assembler code)
* fixed error in thumb2.inc detected by the previous change

git-svn-id: trunk@16633 -

Jonas Maebe 14 年之前
父节点
当前提交
780e75bfac

+ 72 - 2
compiler/arm/aasmcpu.pas

@@ -158,6 +158,7 @@ uses
     type
     type
       taicpu = class(tai_cpu_abstract_sym)
       taicpu = class(tai_cpu_abstract_sym)
          oppostfix : TOpPostfix;
          oppostfix : TOpPostfix;
+         wideformat : boolean;
          roundingmode : troundingmode;
          roundingmode : troundingmode;
          procedure loadshifterop(opidx:longint;const so:tshifterop);
          procedure loadshifterop(opidx:longint;const so:tshifterop);
          procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset);
          procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset);
@@ -246,8 +247,9 @@ uses
     function setroundingmode(i : taicpu;rm : troundingmode) : taicpu;
     function setroundingmode(i : taicpu;rm : troundingmode) : taicpu;
     function setcondition(i : taicpu;c : tasmcond) : taicpu;
     function setcondition(i : taicpu;c : tasmcond) : taicpu;
 
 
-    { inserts pc relative symbols at places where they are reachable }
-    procedure insertpcrelativedata(list,listtoinsert : TAsmList);
+    { inserts pc relative symbols at places where they are reachable
+      and transforms special instructions to valid instruction encodings }
+    procedure finalizearmcode(list,listtoinsert : TAsmList);
     { inserts .pdata section and dummy function prolog needed for arm-wince exception handling }
     { inserts .pdata section and dummy function prolog needed for arm-wince exception handling }
     procedure InsertPData;
     procedure InsertPData;
 
 
@@ -958,6 +960,74 @@ implementation
         curdata.free;
         curdata.free;
       end;
       end;
 
 
+
+    procedure ensurethumb2encodings(list: TAsmList);
+      var
+        curtai: tai;
+        op2reg: TRegister;
+      begin
+        { Do Thumb-2 16bit -> 32bit transformations }
+        curtai:=tai(list.first);
+        while assigned(curtai) do
+          begin
+            case curtai.typ of
+              ait_instruction:
+                begin
+                  case taicpu(curtai).opcode of
+                    A_ADD:
+                      begin
+                        { Set wide flag for ADD Rd,Rn,Rm where registers are over R7(high register set) }
+                        if taicpu(curtai).ops = 3 then
+                          begin
+                            if taicpu(curtai).oper[2]^.typ in [top_reg,top_shifterop] then
+                              begin
+                                if taicpu(curtai).oper[2]^.typ = top_reg then
+                                  op2reg := taicpu(curtai).oper[2]^.reg
+                                else if taicpu(curtai).oper[2]^.shifterop^.rs <> NR_NO then
+                                  op2reg := taicpu(curtai).oper[2]^.shifterop^.rs
+                                else
+                                  op2reg := NR_NO;
+
+                                if op2reg <> NR_NO then
+                                  begin
+                                    if (taicpu(curtai).oper[0]^.reg >= NR_R8) or
+                                       (taicpu(curtai).oper[1]^.reg >= NR_R8) or
+                                       (op2reg >= NR_R8) then
+                                      begin
+                                        taicpu(curtai).wideformat:=true;
+
+                                        { Handle special cases where register rules are violated by optimizer/user }
+                                        { if d == 13 || (d == 15 && S == ‘0’) || n == 15 || m IN [13,15] then UNPREDICTABLE; }
+
+                                        { Transform ADD.W Rx, Ry, R13 into ADD.W Rx, R13, Ry }
+                                        if (op2reg = NR_R13) and (taicpu(curtai).oper[2]^.typ = top_reg) then
+                                          begin
+                                            taicpu(curtai).oper[2]^.reg := taicpu(curtai).oper[1]^.reg;
+                                            taicpu(curtai).oper[1]^.reg := op2reg;
+                                          end;
+                                      end;
+                                  end;
+                              end;
+                          end;
+                      end;
+                  end;
+                end;
+            end;
+
+
+            curtai:=tai(curtai.Next);
+          end;
+      end;
+
+    procedure finalizearmcode(list, listtoinsert: TAsmList);
+      begin
+        insertpcrelativedata(list, listtoinsert);
+
+        { Do Thumb-2 16bit -> 32bit transformations }
+        if current_settings.cputype in cpu_thumb2 then
+          ensurethumb2encodings(list);
+      end;
+
     procedure InsertPData;
     procedure InsertPData;
       var
       var
         prolog: TAsmList;
         prolog: TAsmList;

+ 6 - 2
compiler/arm/agarmgas.pas

@@ -225,17 +225,21 @@ unit agarmgas;
 
 
     Procedure TArmInstrWriter.WriteInstruction(hp : tai);
     Procedure TArmInstrWriter.WriteInstruction(hp : tai);
     var op: TAsmOp;
     var op: TAsmOp;
-        s: string;
+        postfix,s: string;
         i: byte;
         i: byte;
         sep: string[3];
         sep: string[3];
     begin
     begin
       op:=taicpu(hp).opcode;
       op:=taicpu(hp).opcode;
       if current_settings.cputype in cpu_thumb2 then
       if current_settings.cputype in cpu_thumb2 then
         begin
         begin
+          postfix:='';
+          if taicpu(hp).wideformat then
+            postfix:='.w';
+
           if taicpu(hp).ops = 0 then
           if taicpu(hp).ops = 0 then
             s:=#9+gas_op2str[op]+' '+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix]
             s:=#9+gas_op2str[op]+' '+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix]
           else
           else
-            s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix]+cond2str[taicpu(hp).condition]; // Conditional infixes are deprecated in unified syntax
+            s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix]+postfix+cond2str[taicpu(hp).condition]; // Conditional infixes are deprecated in unified syntax
         end
         end
       else
       else
         s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix];
         s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix];

+ 2 - 2
compiler/arm/cgcpu.pas

@@ -2810,12 +2810,12 @@ unit cgcpu;
         inherited init_register_allocators;
         inherited init_register_allocators;
         { currently, we save R14 always, so we can use it }
         { currently, we save R14 always, so we can use it }
         if (target_info.system<>system_arm_darwin) then
         if (target_info.system<>system_arm_darwin) then
-          rg[R_INTREGISTER]:=trgcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
+          rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
               [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
               [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
                RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
                RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
         else
         else
           { r9 is not available on Darwin according to the llvm code generator }
           { r9 is not available on Darwin according to the llvm code generator }
-          rg[R_INTREGISTER]:=trgcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
+          rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
               [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
               [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
                RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
                RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
         rg[R_FPUREGISTER]:=trgcputhumb2.create(R_FPUREGISTER,R_SUBNONE,
         rg[R_FPUREGISTER]:=trgcputhumb2.create(R_FPUREGISTER,R_SUBNONE,

+ 2 - 0
compiler/arm/raarm.pas

@@ -36,6 +36,7 @@ unit raarm;
 
 
       TARMInstruction=class(TInstruction)
       TARMInstruction=class(TInstruction)
         oppostfix : toppostfix;
         oppostfix : toppostfix;
+        wideformat : boolean; // For wide(32bit) instructions of the thumb-2 instruction set
         function ConcatInstruction(p:TAsmList) : tai;override;
         function ConcatInstruction(p:TAsmList) : tai;override;
       end;
       end;
 
 
@@ -48,6 +49,7 @@ unit raarm;
       begin
       begin
         result:=inherited ConcatInstruction(p);
         result:=inherited ConcatInstruction(p);
         (result as taicpu).oppostfix:=oppostfix;
         (result as taicpu).oppostfix:=oppostfix;
+        (result as taicpu).wideformat:=wideformat;
       end;
       end;
 
 
 
 

+ 12 - 0
compiler/arm/raarmgas.pas

@@ -32,6 +32,7 @@ Unit raarmgas;
     type
     type
       tarmattreader = class(tattreader)
       tarmattreader = class(tattreader)
         actoppostfix : TOpPostfix;
         actoppostfix : TOpPostfix;
+        actwideformat : boolean;
         function is_asmopcode(const s: string):boolean;override;
         function is_asmopcode(const s: string):boolean;override;
         function is_register(const s:string):boolean;override;
         function is_register(const s:string):boolean;override;
         procedure handleopcode;override;
         procedure handleopcode;override;
@@ -916,6 +917,7 @@ Unit raarmgas;
             Opcode:=ActOpcode;
             Opcode:=ActOpcode;
             condition:=ActCondition;
             condition:=ActCondition;
             oppostfix:=actoppostfix;
             oppostfix:=actoppostfix;
+            wideformat:=actwideformat;
           end;
           end;
 
 
         { We are reading operands, so opcode will be an AS_ID }
         { We are reading operands, so opcode will be an AS_ID }
@@ -1056,6 +1058,15 @@ Unit raarmgas;
                   end;
                   end;
               end;
               end;
           end;
           end;
+        { check for format postfix }
+        if length(hs)>0 then
+          begin
+            if upcase(copy(hs,1,2)) = '.W' then
+              begin
+                actwideformat:=true;
+                delete(hs,1,2);
+              end;
+          end;
         { if we stripped all postfixes, it's a valid opcode }
         { if we stripped all postfixes, it's a valid opcode }
         is_asmopcode:=length(hs)=0;
         is_asmopcode:=length(hs)=0;
       end;
       end;
@@ -1094,6 +1105,7 @@ Unit raarmgas;
         instr.ConcatInstruction(curlist);
         instr.ConcatInstruction(curlist);
         instr.Free;
         instr.Free;
         actoppostfix:=PF_None;
         actoppostfix:=PF_None;
+        actwideformat:=false;
       end;
       end;
 
 
 
 

+ 42 - 0
compiler/arm/rgcpu.pas

@@ -46,6 +46,10 @@ unit rgcpu;
          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;
 
 
+       trgintcputhumb2 = class(trgcputhumb2)
+         procedure add_cpu_interferences(p : tai);override;
+       end;
+
        trgintcpu = class(trgcpu)
        trgintcpu = class(trgcpu)
          procedure add_cpu_interferences(p : tai);override;
          procedure add_cpu_interferences(p : tai);override;
        end;
        end;
@@ -57,6 +61,44 @@ unit rgcpu;
       cgobj,
       cgobj,
       procinfo;
       procinfo;
 
 
+    procedure trgintcputhumb2.add_cpu_interferences(p: tai);
+      begin
+        if p.typ=ait_instruction then
+          begin
+            case taicpu(p).opcode of
+              A_ADD:
+                begin
+                  if taicpu(p).ops = 3 then
+                    begin
+                      if (taicpu(p).oper[0]^.typ = top_reg) and
+                         (taicpu(p).oper[1]^.typ = top_reg) and
+                         (taicpu(p).oper[2]^.typ in [top_reg, top_shifterop]) then
+                        begin
+                          { if d == 13 || (d == 15 && S == ‘0’) || n == 15 || m IN [13,15] then UNPREDICTABLE; }
+                          add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R13);
+                          if taicpu(p).oppostfix <> PF_S then
+                            add_edge(getsupreg(taicpu(p).oper[0]^.reg), RS_R15);
+
+                          add_edge(getsupreg(taicpu(p).oper[1]^.reg), RS_R15);
+
+                          if (taicpu(p).oper[2]^.typ = top_shifterop) and
+                             (taicpu(p).oper[2]^.shifterop^.rs <> NR_NO) then
+                            begin
+                              add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R13);
+                              add_edge(getsupreg(taicpu(p).oper[2]^.shifterop^.rs), RS_R15);
+                            end
+                          else if (taicpu(p).oper[2]^.typ = top_reg) then
+                            begin
+                              add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R13);
+                              add_edge(getsupreg(taicpu(p).oper[2]^.reg), RS_R15);
+                            end;
+                        end;
+                    end;
+                end;
+            end;
+          end;
+      end;
+
 
 
     procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
     procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
       var
       var

+ 1 - 1
compiler/psub.pas

@@ -1227,7 +1227,7 @@ implementation
 
 
 {$ifdef ARM}
 {$ifdef ARM}
             { because of the limited constant size of the arm, all data access is done pc relative }
             { because of the limited constant size of the arm, all data access is done pc relative }
-            insertpcrelativedata(aktproccode,aktlocaldata);
+            finalizearmcode(aktproccode,aktlocaldata);
 {$endif ARM}
 {$endif ARM}
 
 
             { Add end symbol and debug info }
             { Add end symbol and debug info }

+ 19 - 0
compiler/raatt.pas

@@ -258,6 +258,25 @@ unit raatt;
                end
                end
            end;
            end;
 {$endif POWERPC}
 {$endif POWERPC}
+{$if defined(ARM)}
+           { Thumb-2 instructions can have a .W postfix to indicate 32bit instructions
+           }
+           case c of
+             '.':
+               begin
+                 actasmpattern:=actasmpattern+c;
+                 c:=current_scanner.asmgetchar;
+
+                 if upcase(c) = 'W' then
+                   begin
+                     actasmpattern:=actasmpattern+c;
+                     c:=current_scanner.asmgetchar;
+                   end
+                 else
+                   internalerror(2010122301);
+               end
+           end;
+{$endif ARM}
            { Opcode ? }
            { Opcode ? }
            If is_asmopcode(upper(actasmpattern)) then
            If is_asmopcode(upper(actasmpattern)) then
             Begin
             Begin

+ 1 - 1
rtl/arm/thumb2.inc

@@ -148,7 +148,7 @@ asm
         moveq pc,lr
         moveq pc,lr
         rsb     r1,r1,#7
         rsb     r1,r1,#7
         mov     r1,r1,lsl #2
         mov     r1,r1,lsl #2
-        add     pc,pc,r1
+        add     pc,r1
         mov     r0,r0
         mov     r0,r0
         strb r2,[r3],#1
         strb r2,[r3],#1
         strb r2,[r3],#1
         strb r2,[r3],#1