Browse Source

* patch by Jeppe Johansen to add support for handling different flags for xPSR regs,
and add usermode parsing of LDM/STM ops
This patch basically extends the ARM assembly reader a bit to properly parse CPSR and
SPSR flags for the MSR opcode, and allows the reader to understand
the ^ modifer for register lists for STMxx and LDMxx.

Previously the following combinations weren't possible in straight assembler:
MRS R0, CPSR
MRS R0, SPSR
MSR CPSR_CX, R0
LDMIA SP, {R0-R15}^
etc..

git-svn-id: trunk@22502 -

florian 13 năm trước cách đây
mục cha
commit
54d3d736f5

+ 1 - 0
.gitattributes

@@ -12888,6 +12888,7 @@ tests/webtbs/tw2289.pp svneol=native#text/plain
 tests/webtbs/tw2291.pp svneol=native#text/plain
 tests/webtbs/tw2291.pp svneol=native#text/plain
 tests/webtbs/tw2294.pp svneol=native#text/plain
 tests/webtbs/tw2294.pp svneol=native#text/plain
 tests/webtbs/tw2296.pp svneol=native#text/plain
 tests/webtbs/tw2296.pp svneol=native#text/plain
+tests/webtbs/tw22992.pp svneol=native#text/pascal
 tests/webtbs/tw2300.pp svneol=native#text/plain
 tests/webtbs/tw2300.pp svneol=native#text/plain
 tests/webtbs/tw2305.pp svneol=native#text/plain
 tests/webtbs/tw2305.pp svneol=native#text/plain
 tests/webtbs/tw2306.pp svneol=native#text/plain
 tests/webtbs/tw2306.pp svneol=native#text/plain

+ 3 - 1
compiler/aasmtai.pas

@@ -201,6 +201,7 @@ interface
        ,top_shifterop
        ,top_shifterop
        ,top_conditioncode
        ,top_conditioncode
        ,top_modeflags
        ,top_modeflags
+       ,top_specialreg
 {$endif arm}
 {$endif arm}
 {$ifdef m68k}
 {$ifdef m68k}
        { m68k only }
        { m68k only }
@@ -241,10 +242,11 @@ interface
           { local varsym that will be inserted in pass_generate_code }
           { local varsym that will be inserted in pass_generate_code }
           top_local  : (localoper:plocaloper);
           top_local  : (localoper:plocaloper);
       {$ifdef arm}
       {$ifdef arm}
-          top_regset : (regset:^tcpuregisterset; regtyp: tregistertype; subreg: tsubregister);
+          top_regset : (regset:^tcpuregisterset; regtyp: tregistertype; subreg: tsubregister; usermode: boolean);
           top_shifterop : (shifterop : pshifterop);
           top_shifterop : (shifterop : pshifterop);
           top_conditioncode : (cc : TAsmCond);
           top_conditioncode : (cc : TAsmCond);
           top_modeflags : (modeflags : tcpumodeflags);
           top_modeflags : (modeflags : tcpumodeflags);
+          top_specialreg : (specialreg:tregister; specialflags:tspecialregflags);
       {$endif arm}
       {$endif arm}
       {$ifdef m68k}
       {$ifdef m68k}
           top_regset : (regset:^tcpuregisterset);
           top_regset : (regset:^tcpuregisterset);

+ 27 - 2
compiler/arm/aasmcpu.pas

@@ -161,9 +161,10 @@ uses
          wideformat : boolean;
          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; ausermode: boolean=false);
          procedure loadconditioncode(opidx:longint;const cond:tasmcond);
          procedure loadconditioncode(opidx:longint;const cond:tasmcond);
          procedure loadmodeflags(opidx:longint;const flags:tcpumodeflags);
          procedure loadmodeflags(opidx:longint;const flags:tcpumodeflags);
+         procedure loadspecialreg(opidx:longint;const areg:tregister; const aflags:tspecialregflags);
          constructor op_none(op : tasmop);
          constructor op_none(op : tasmop);
 
 
          constructor op_reg(op : tasmop;_op1 : tregister);
          constructor op_reg(op : tasmop;_op1 : tregister);
@@ -192,6 +193,9 @@ uses
          constructor op_modeflags(op: tasmop; flags: tcpumodeflags);
          constructor op_modeflags(op: tasmop; flags: tcpumodeflags);
          constructor op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint);
          constructor op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint);
 
 
+         { MSR }
+         constructor op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister);
+
          { *M*LL }
          { *M*LL }
          constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
          constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
 
 
@@ -286,7 +290,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure taicpu.loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset);
+    procedure taicpu.loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset; ausermode: boolean);
       var
       var
         i : byte;
         i : byte;
       begin
       begin
@@ -301,6 +305,7 @@ implementation
            regset^:=s;
            regset^:=s;
            regtyp:=regsetregtype;
            regtyp:=regsetregtype;
            subreg:=regsetsubregtype;
            subreg:=regsetsubregtype;
+           usermode:=ausermode;
            typ:=top_regset;
            typ:=top_regset;
            case regsetregtype of
            case regsetregtype of
              R_INTREGISTER:
              R_INTREGISTER:
@@ -345,6 +350,19 @@ implementation
          end;
          end;
       end;
       end;
 
 
+    procedure taicpu.loadspecialreg(opidx: longint; const areg: tregister; const aflags: tspecialregflags);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_specialreg then
+             clearop(opidx);
+           specialreg:=areg;
+           specialflags:=aflags;
+           typ:=top_specialreg;
+         end;
+      end;
+
 {*****************************************************************************
 {*****************************************************************************
                                  taicpu Constructors
                                  taicpu Constructors
 *****************************************************************************}
 *****************************************************************************}
@@ -479,6 +497,13 @@ implementation
         loadconst(1,a);
         loadconst(1,a);
       end;
       end;
 
 
+    constructor taicpu.op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister);
+      begin
+        inherited create(op);
+        ops:=2;
+        loadspecialreg(0,specialreg,specialregflags);
+        loadreg(1,_op2);
+      end;
 
 
      constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
      constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
        begin
        begin

+ 14 - 0
compiler/arm/agarmgas.pas

@@ -215,6 +215,8 @@ unit agarmgas;
                     first:=false;
                     first:=false;
                   end;
                   end;
               getopstr:=getopstr+'}';
               getopstr:=getopstr+'}';
+              if o.usermode then
+                getopstr:=getopstr+'^';
             end;
             end;
           top_conditioncode:
           top_conditioncode:
             getopstr:=cond2str[o.cc];
             getopstr:=cond2str[o.cc];
@@ -238,6 +240,18 @@ unit agarmgas;
               end
               end
             else
             else
               getopstr:=getreferencestring(o.ref^);
               getopstr:=getreferencestring(o.ref^);
+          top_specialreg:
+            begin
+              getopstr:=gas_regname(o.specialreg);
+              if o.specialflags<>[] then
+                begin
+                  getopstr:=getopstr+'_';
+                  if srC in o.specialflags then getopstr:=getopstr+'c';
+                  if srX in o.specialflags then getopstr:=getopstr+'x';
+                  if srF in o.specialflags then getopstr:=getopstr+'f';
+                  if srS in o.specialflags then getopstr:=getopstr+'s';
+                end;
+            end
           else
           else
             internalerror(2002070604);
             internalerror(2002070604);
         end;
         end;

+ 2 - 1
compiler/arm/armreg.dat

@@ -107,5 +107,6 @@ D30,$04,$07,$1E,d30,0,0
 D31,$04,$07,$1F,d31,0,0
 D31,$04,$07,$1F,d31,0,0
 
 
 ; special registers
 ; special registers
-CPSR_C,$05,$00,$00,cpsr_c,0,0
+CPSR,$05,$00,$00,cpsr,0,0
 FPSCR,$05,$00,$01,fpscr,0,0
 FPSCR,$05,$00,$01,fpscr,0,0
+SPSR,$05,$00,$02,spsr,0,0

+ 5 - 2
compiler/arm/cpubase.pas

@@ -215,6 +215,9 @@ unit cpubase;
       tcpumodeflag = (mfA, mfI, mfF);
       tcpumodeflag = (mfA, mfI, mfF);
       tcpumodeflags = set of tcpumodeflag;
       tcpumodeflags = set of tcpumodeflag;
 
 
+      tspecialregflag = (srC, srX, srS, srF);
+      tspecialregflags = set of tspecialregflag;
+
 {*****************************************************************************
 {*****************************************************************************
                                  Constants
                                  Constants
 *****************************************************************************}
 *****************************************************************************}
@@ -296,8 +299,8 @@ unit cpubase;
       { Offset where the parent framepointer is pushed }
       { Offset where the parent framepointer is pushed }
       PARENT_FRAMEPOINTER_OFFSET = 0;
       PARENT_FRAMEPOINTER_OFFSET = 0;
 
 
-      NR_DEFAULTFLAGS = NR_CPSR_C;
-      RS_DEFAULTFLAGS = RS_CPSR_C;
+      NR_DEFAULTFLAGS = NR_CPSR;
+      RS_DEFAULTFLAGS = RS_CPSR;
 
 
       { Low part of 64bit return value }
       { Low part of 64bit return value }
       function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}
       function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}

+ 74 - 1
compiler/arm/raarmgas.pas

@@ -38,6 +38,7 @@ Unit raarmgas;
         procedure handleopcode;override;
         procedure handleopcode;override;
         procedure BuildReference(oper : tarmoperand);
         procedure BuildReference(oper : tarmoperand);
         procedure BuildOperand(oper : tarmoperand);
         procedure BuildOperand(oper : tarmoperand);
+        procedure BuildSpecialreg(oper : tarmoperand);
         function TryBuildShifterOp(oper : tarmoperand) : boolean;
         function TryBuildShifterOp(oper : tarmoperand) : boolean;
         procedure BuildOpCode(instr : tarminstruction);
         procedure BuildOpCode(instr : tarminstruction);
         procedure ReadSym(oper : tarmoperand);
         procedure ReadSym(oper : tarmoperand);
@@ -925,6 +926,13 @@ Unit raarmgas;
               oper.opr.regtype:=regtype;
               oper.opr.regtype:=regtype;
               oper.opr.subreg:=subreg;
               oper.opr.subreg:=subreg;
               oper.opr.regset:=registerset;
               oper.opr.regset:=registerset;
+              if actasmtoken=AS_XOR then
+                begin
+                  consume(AS_XOR);
+                  oper.opr.usermode:=true;
+                end
+              else
+                oper.opr.usermode:=false;
               if (registerset=[]) then
               if (registerset=[]) then
                 Message(asmr_e_empty_regset);
                 Message(asmr_e_empty_regset);
             end;
             end;
@@ -939,6 +947,68 @@ Unit raarmgas;
         end; { end case }
         end; { end case }
       end;
       end;
 
 
+    procedure tarmattreader.BuildSpecialreg(oper: tarmoperand);
+      var
+        hs, reg : String;
+        ch : char;
+        i, t : longint;
+        hreg : tregister;
+        flags : tspecialregflags;
+      begin
+        case actasmtoken of
+          AS_REGISTER:
+            begin
+              oper.opr.typ:=OPR_REGISTER;
+              oper.opr.reg:=actasmregister;
+              Consume(AS_REGISTER);
+            end;
+          AS_ID:
+            begin
+              t := pos('_', actasmpattern);
+              if t > 0 then
+                begin
+                  hs:=lower(actasmpattern);
+                  reg:=copy(hs, 1, t-1);
+                  delete(hs, 1, t);
+
+                  if length(hs) < 1 then
+                    Message(asmr_e_invalid_operand_type);
+
+                  if reg = 'cpsr' then
+                    hreg:=NR_CPSR
+                  else if reg='spsr' then
+                    hreg:=NR_SPSR
+                  else
+                    Message(asmr_e_invalid_register);
+
+                  flags:=[];
+                  for i := 1 to length(hs) do
+                    begin
+                      ch:=hs[i];
+                      if ch='c' then
+                        include(flags, srC)
+                      else if ch='x' then
+                        include(flags, srX)
+                      else if ch='f' then
+                        include(flags, srF)
+                      else if ch='s' then
+                        include(flags, srS)
+                      else
+                        message(asmr_e_invalid_operand_type);
+                    end;
+
+                  oper.opr.typ:=OPR_SPECIALREG;
+                  oper.opr.specialreg:=hreg;
+                  oper.opr.specialregflags:=flags;
+
+                  consume(AS_ID);
+                end
+              else
+                Message(asmr_e_invalid_operand_type); // Otherwise it would have been seen as a AS_REGISTER
+            end;
+        end;
+      end;
+
 
 
 {*****************************************************************************
 {*****************************************************************************
                                 tarmattreader
                                 tarmattreader
@@ -1001,7 +1071,10 @@ Unit raarmgas;
                 break;
                 break;
               end;
               end;
           else
           else
-            BuildOperand(instr.Operands[operandnum] as tarmoperand);
+            if (instr.opcode = A_MSR) and (operandnum = 1) then
+              BuildSpecialreg(instr.Operands[operandnum] as tarmoperand)
+            else
+              BuildOperand(instr.Operands[operandnum] as tarmoperand);
           end; { end case }
           end; { end case }
         until false;
         until false;
         instr.Ops:=operandnum;
         instr.Ops:=operandnum;

+ 2 - 1
compiler/arm/rarmcon.inc

@@ -88,5 +88,6 @@ NR_D28 = tregister($0407001C);
 NR_D29 = tregister($0407001D);
 NR_D29 = tregister($0407001D);
 NR_D30 = tregister($0407001E);
 NR_D30 = tregister($0407001E);
 NR_D31 = tregister($0407001F);
 NR_D31 = tregister($0407001F);
-NR_CPSR_C = tregister($05000000);
+NR_CPSR = tregister($05000000);
 NR_FPSCR = tregister($05000001);
 NR_FPSCR = tregister($05000001);
+NR_SPSR = tregister($05000002);

+ 1 - 0
compiler/arm/rarmdwa.inc

@@ -89,4 +89,5 @@
 0,
 0,
 0,
 0,
 0,
 0,
+0,
 0
 0

+ 1 - 1
compiler/arm/rarmnor.inc

@@ -1,2 +1,2 @@
 { don't edit, this file is generated from armreg.dat }
 { don't edit, this file is generated from armreg.dat }
-91
+92

+ 2 - 1
compiler/arm/rarmnum.inc

@@ -89,4 +89,5 @@ tregister($0407001D),
 tregister($0407001E),
 tregister($0407001E),
 tregister($0407001F),
 tregister($0407001F),
 tregister($05000000),
 tregister($05000000),
-tregister($05000001)
+tregister($05000001),
+tregister($05000002)

+ 2 - 1
compiler/arm/rarmrni.inc

@@ -89,4 +89,5 @@
 87,
 87,
 88,
 88,
 89,
 89,
-90
+90,
+91

+ 2 - 1
compiler/arm/rarmsri.inc

@@ -89,4 +89,5 @@
 34,
 34,
 35,
 35,
 37,
 37,
-38
+38,
+91

+ 1 - 0
compiler/arm/rarmsta.inc

@@ -89,4 +89,5 @@
 0,
 0,
 0,
 0,
 0,
 0,
+0,
 0
 0

+ 3 - 2
compiler/arm/rarmstd.inc

@@ -88,5 +88,6 @@
 'd29',
 'd29',
 'd30',
 'd30',
 'd31',
 'd31',
-'cpsr_c',
-'fpscr'
+'cpsr',
+'fpscr',
+'spsr'

+ 2 - 1
compiler/arm/rarmsup.inc

@@ -88,5 +88,6 @@ RS_D28 = $1C;
 RS_D29 = $1D;
 RS_D29 = $1D;
 RS_D30 = $1E;
 RS_D30 = $1E;
 RS_D31 = $1F;
 RS_D31 = $1F;
-RS_CPSR_C = $00;
+RS_CPSR = $00;
 RS_FPSCR = $01;
 RS_FPSCR = $01;
+RS_SPSR = $02;

+ 6 - 3
compiler/rautils.pas

@@ -72,7 +72,7 @@ Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
 
 
 type
 type
   TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
   TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
-            OPR_REFERENCE,OPR_REGISTER,OPR_REGLIST,OPR_COND,OPR_REGSET,OPR_SHIFTEROP,OPR_MODEFLAGS);
+            OPR_REFERENCE,OPR_REGISTER,OPR_REGLIST,OPR_COND,OPR_REGSET,OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG);
 
 
   TOprRec = record
   TOprRec = record
     case typ:TOprType of
     case typ:TOprType of
@@ -92,10 +92,11 @@ type
       OPR_COND      : (cond : tasmcond);
       OPR_COND      : (cond : tasmcond);
 {$endif POWERPC64}
 {$endif POWERPC64}
 {$ifdef arm}
 {$ifdef arm}
-      OPR_REGSET    : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister);
+      OPR_REGSET    : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister; usermode: boolean);
       OPR_SHIFTEROP : (shifterop : tshifterop);
       OPR_SHIFTEROP : (shifterop : tshifterop);
       OPR_COND      : (cc : tasmcond);
       OPR_COND      : (cc : tasmcond);
       OPR_MODEFLAGS : (flags : tcpumodeflags);
       OPR_MODEFLAGS : (flags : tcpumodeflags);
+      OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags);
 {$endif arm}
 {$endif arm}
   end;
   end;
 
 
@@ -1091,13 +1092,15 @@ end;
                 ai.loadref(i-1,ref);
                 ai.loadref(i-1,ref);
 {$ifdef ARM}
 {$ifdef ARM}
               OPR_REGSET:
               OPR_REGSET:
-                ai.loadregset(i-1,regtype,subreg,regset);
+                ai.loadregset(i-1,regtype,subreg,regset,usermode);
               OPR_SHIFTEROP:
               OPR_SHIFTEROP:
                 ai.loadshifterop(i-1,shifterop);
                 ai.loadshifterop(i-1,shifterop);
               OPR_COND:
               OPR_COND:
                 ai.loadconditioncode(i-1,cc);
                 ai.loadconditioncode(i-1,cc);
               OPR_MODEFLAGS:
               OPR_MODEFLAGS:
                 ai.loadmodeflags(i-1,flags);
                 ai.loadmodeflags(i-1,flags);
+              OPR_SPECIALREG:
+                ai.loadspecialreg(i-1,specialreg,specialregflags);
 {$endif ARM}
 {$endif ARM}
               { ignore wrong operand }
               { ignore wrong operand }
               OPR_NONE:
               OPR_NONE:

+ 12 - 0
tests/webtbs/tw22992.pp

@@ -0,0 +1,12 @@
+{ %norun }
+{ %cpu=arm }
+
+begin
+  asm
+    MRS R0, CPSR
+    MRS R0, SPSR
+    MSR CPSR_CX, R0
+    LDMIA SP, {R0-R15}^
+  end;
+end.
+