* 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 -
This commit is contained in:
florian 2012-09-29 08:23:40 +00:00
parent 0a755be6fe
commit 54d3d736f5
18 changed files with 160 additions and 18 deletions

1
.gitattributes vendored
View File

@ -12888,6 +12888,7 @@ tests/webtbs/tw2289.pp svneol=native#text/plain
tests/webtbs/tw2291.pp svneol=native#text/plain
tests/webtbs/tw2294.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/tw2305.pp svneol=native#text/plain
tests/webtbs/tw2306.pp svneol=native#text/plain

View File

@ -201,6 +201,7 @@ interface
,top_shifterop
,top_conditioncode
,top_modeflags
,top_specialreg
{$endif arm}
{$ifdef m68k}
{ m68k only }
@ -241,10 +242,11 @@ interface
{ local varsym that will be inserted in pass_generate_code }
top_local : (localoper:plocaloper);
{$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_conditioncode : (cc : TAsmCond);
top_modeflags : (modeflags : tcpumodeflags);
top_specialreg : (specialreg:tregister; specialflags:tspecialregflags);
{$endif arm}
{$ifdef m68k}
top_regset : (regset:^tcpuregisterset);

View File

@ -161,9 +161,10 @@ uses
wideformat : boolean;
roundingmode : troundingmode;
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 loadmodeflags(opidx:longint;const flags:tcpumodeflags);
procedure loadspecialreg(opidx:longint;const areg:tregister; const aflags:tspecialregflags);
constructor op_none(op : tasmop);
constructor op_reg(op : tasmop;_op1 : tregister);
@ -192,6 +193,9 @@ uses
constructor op_modeflags(op: tasmop; flags: tcpumodeflags);
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 }
constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
@ -286,7 +290,7 @@ implementation
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
i : byte;
begin
@ -301,6 +305,7 @@ implementation
regset^:=s;
regtyp:=regsetregtype;
subreg:=regsetsubregtype;
usermode:=ausermode;
typ:=top_regset;
case regsetregtype of
R_INTREGISTER:
@ -345,6 +350,19 @@ implementation
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
*****************************************************************************}
@ -479,6 +497,13 @@ implementation
loadconst(1,a);
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);
begin

View File

@ -215,6 +215,8 @@ unit agarmgas;
first:=false;
end;
getopstr:=getopstr+'}';
if o.usermode then
getopstr:=getopstr+'^';
end;
top_conditioncode:
getopstr:=cond2str[o.cc];
@ -238,6 +240,18 @@ unit agarmgas;
end
else
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
internalerror(2002070604);
end;

View File

@ -107,5 +107,6 @@ D30,$04,$07,$1E,d30,0,0
D31,$04,$07,$1F,d31,0,0
; 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
SPSR,$05,$00,$02,spsr,0,0

View File

@ -215,6 +215,9 @@ unit cpubase;
tcpumodeflag = (mfA, mfI, mfF);
tcpumodeflags = set of tcpumodeflag;
tspecialregflag = (srC, srX, srS, srF);
tspecialregflags = set of tspecialregflag;
{*****************************************************************************
Constants
*****************************************************************************}
@ -296,8 +299,8 @@ unit cpubase;
{ Offset where the parent framepointer is pushed }
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 }
function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}

View File

@ -38,6 +38,7 @@ Unit raarmgas;
procedure handleopcode;override;
procedure BuildReference(oper : tarmoperand);
procedure BuildOperand(oper : tarmoperand);
procedure BuildSpecialreg(oper : tarmoperand);
function TryBuildShifterOp(oper : tarmoperand) : boolean;
procedure BuildOpCode(instr : tarminstruction);
procedure ReadSym(oper : tarmoperand);
@ -925,6 +926,13 @@ Unit raarmgas;
oper.opr.regtype:=regtype;
oper.opr.subreg:=subreg;
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
Message(asmr_e_empty_regset);
end;
@ -939,6 +947,68 @@ Unit raarmgas;
end; { end case }
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
@ -1001,7 +1071,10 @@ Unit raarmgas;
break;
end;
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 }
until false;
instr.Ops:=operandnum;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -72,7 +72,7 @@ Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
type
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
case typ:TOprType of
@ -92,10 +92,11 @@ type
OPR_COND : (cond : tasmcond);
{$endif POWERPC64}
{$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_COND : (cc : tasmcond);
OPR_MODEFLAGS : (flags : tcpumodeflags);
OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags);
{$endif arm}
end;
@ -1091,13 +1092,15 @@ end;
ai.loadref(i-1,ref);
{$ifdef ARM}
OPR_REGSET:
ai.loadregset(i-1,regtype,subreg,regset);
ai.loadregset(i-1,regtype,subreg,regset,usermode);
OPR_SHIFTEROP:
ai.loadshifterop(i-1,shifterop);
OPR_COND:
ai.loadconditioncode(i-1,cc);
OPR_MODEFLAGS:
ai.loadmodeflags(i-1,flags);
OPR_SPECIALREG:
ai.loadspecialreg(i-1,specialreg,specialregflags);
{$endif ARM}
{ ignore wrong operand }
OPR_NONE:

12
tests/webtbs/tw22992.pp Normal file
View File

@ -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.