mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 11:24:14 +02:00
* 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:
parent
0a755be6fe
commit
54d3d736f5
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -89,4 +89,5 @@
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
|
@ -1,2 +1,2 @@
|
||||
{ don't edit, this file is generated from armreg.dat }
|
||||
91
|
||||
92
|
||||
|
@ -89,4 +89,5 @@ tregister($0407001D),
|
||||
tregister($0407001E),
|
||||
tregister($0407001F),
|
||||
tregister($05000000),
|
||||
tregister($05000001)
|
||||
tregister($05000001),
|
||||
tregister($05000002)
|
||||
|
@ -89,4 +89,5 @@
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90
|
||||
90,
|
||||
91
|
||||
|
@ -89,4 +89,5 @@
|
||||
34,
|
||||
35,
|
||||
37,
|
||||
38
|
||||
38,
|
||||
91
|
||||
|
@ -89,4 +89,5 @@
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
|
@ -88,5 +88,6 @@
|
||||
'd29',
|
||||
'd30',
|
||||
'd31',
|
||||
'cpsr_c',
|
||||
'fpscr'
|
||||
'cpsr',
|
||||
'fpscr',
|
||||
'spsr'
|
||||
|
@ -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;
|
||||
|
@ -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
12
tests/webtbs/tw22992.pp
Normal 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.
|
||||
|
Loading…
Reference in New Issue
Block a user