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 -
This commit is contained in:
Jonas Maebe 2010-12-24 15:54:39 +00:00
parent 8cbef5627e
commit 780e75bfac
9 changed files with 157 additions and 8 deletions

View File

@ -158,6 +158,7 @@ uses
type
taicpu = class(tai_cpu_abstract_sym)
oppostfix : TOpPostfix;
wideformat : boolean;
roundingmode : troundingmode;
procedure loadshifterop(opidx:longint;const so:tshifterop);
procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset);
@ -246,8 +247,9 @@ uses
function setroundingmode(i : taicpu;rm : troundingmode) : 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 }
procedure InsertPData;
@ -958,6 +960,74 @@ implementation
curdata.free;
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;
var
prolog: TAsmList;

View File

@ -225,17 +225,21 @@ unit agarmgas;
Procedure TArmInstrWriter.WriteInstruction(hp : tai);
var op: TAsmOp;
s: string;
postfix,s: string;
i: byte;
sep: string[3];
begin
op:=taicpu(hp).opcode;
if current_settings.cputype in cpu_thumb2 then
begin
postfix:='';
if taicpu(hp).wideformat then
postfix:='.w';
if taicpu(hp).ops = 0 then
s:=#9+gas_op2str[op]+' '+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix]
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
else
s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix];

View File

@ -2810,12 +2810,12 @@ unit cgcpu;
inherited init_register_allocators;
{ currently, we save R14 always, so we can use it }
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_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
else
{ 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_R10,RS_R12,RS_R14],first_int_imreg,[]);
rg[R_FPUREGISTER]:=trgcputhumb2.create(R_FPUREGISTER,R_SUBNONE,

View File

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

View File

@ -32,6 +32,7 @@ Unit raarmgas;
type
tarmattreader = class(tattreader)
actoppostfix : TOpPostfix;
actwideformat : boolean;
function is_asmopcode(const s: string):boolean;override;
function is_register(const s:string):boolean;override;
procedure handleopcode;override;
@ -916,6 +917,7 @@ Unit raarmgas;
Opcode:=ActOpcode;
condition:=ActCondition;
oppostfix:=actoppostfix;
wideformat:=actwideformat;
end;
{ We are reading operands, so opcode will be an AS_ID }
@ -1056,6 +1058,15 @@ Unit raarmgas;
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 }
is_asmopcode:=length(hs)=0;
end;
@ -1094,6 +1105,7 @@ Unit raarmgas;
instr.ConcatInstruction(curlist);
instr.Free;
actoppostfix:=PF_None;
actwideformat:=false;
end;

View File

@ -46,6 +46,10 @@ unit rgcpu;
procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
end;
trgintcputhumb2 = class(trgcputhumb2)
procedure add_cpu_interferences(p : tai);override;
end;
trgintcpu = class(trgcpu)
procedure add_cpu_interferences(p : tai);override;
end;
@ -57,6 +61,44 @@ unit rgcpu;
cgobj,
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);
var

View File

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

View File

@ -258,6 +258,25 @@ unit raatt;
end
end;
{$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 ? }
If is_asmopcode(upper(actasmpattern)) then
Begin

View File

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