* Properly fill treference.alignment when variable is loaded by tcgloadnode. It allows code generator to insert unaligned handling if needed.

* Improved generic a_load_ref_reg_unaligned if ref alignment is 2.
* Improved unaligned load/store of register for ARM.
* It fixes passing records by value on ARM.
+ New test.

git-svn-id: trunk@10681 -
This commit is contained in:
yury 2008-04-16 23:01:20 +00:00
parent 24be2c31f7
commit ec943198fd
6 changed files with 168 additions and 89 deletions

1
.gitattributes vendored
View File

@ -7069,6 +7069,7 @@ tests/test/cg/tobjsiz2.pp svneol=native#text/plain
tests/test/cg/tobjsize.pp svneol=native#text/plain
tests/test/cg/tpara1.pp svneol=native#text/plain
tests/test/cg/tpara2.pp svneol=native#text/plain
tests/test/cg/tpara3.pp svneol=native#text/plain
tests/test/cg/tprintf.pp svneol=native#text/plain
tests/test/cg/tprintf2.pp svneol=native#text/plain
tests/test/cg/tprintf3.pp svneol=native#text/plain

View File

@ -791,7 +791,7 @@ unit cgcpu;
else
InternalError(200308295);
end;
if ref.alignment<>0 then
if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
begin
if target_info.endian=endian_big then
dir:=-1
@ -812,21 +812,35 @@ unit cgcpu;
end;
OS_32,OS_S32:
begin
shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
tmpreg:=getintregister(list,OS_INT);
usedtmpref:=ref;
if target_info.endian=endian_big then
inc(usedtmpref.offset,3);
usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
shifterop_reset(so);so.shiftmode:=SM_LSR;
if ref.alignment=2 then
begin
so.shiftimm:=16;
if target_info.endian=endian_big then
inc(usedtmpref.offset,2);
usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
inc(usedtmpref.offset,dir*2);
a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
end
else
begin
so.shiftimm:=8;
if target_info.endian=endian_big then
inc(usedtmpref.offset,3);
usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
end;
end
else
handle_load_store(list,A_STR,oppostfix,reg,ref);
@ -841,7 +855,7 @@ unit cgcpu;
var
oppostfix:toppostfix;
usedtmpref: treference;
tmpreg,tmpreg2,tmpreg3 : tregister;
tmpreg,tmpreg2 : tregister;
so : tshifterop;
dir : integer;
begin
@ -863,7 +877,7 @@ unit cgcpu;
else
InternalError(200308297);
end;
if Ref.alignment<>0 then
if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
begin
if target_info.endian=endian_big then
dir:=-1
@ -881,9 +895,9 @@ unit cgcpu;
(reg=ref.index) or
(reg=ref.base) then
begin
tmpreg3:=getintregister(list,OS_INT);
a_loadaddr_ref_reg(list,ref,tmpreg3);
reference_reset_base(usedtmpref,tmpreg3,0);
tmpreg2:=getintregister(list,OS_INT);
a_loadaddr_ref_reg(list,ref,tmpreg2);
reference_reset_base(usedtmpref,tmpreg2,0);
end
else
usedtmpref:=ref;
@ -892,19 +906,17 @@ unit cgcpu;
inc(usedtmpref.offset,1);
shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
tmpreg:=getintregister(list,OS_INT);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
inc(usedtmpref.offset,dir);
tmpreg2:=getintregister(list,OS_INT);
if FromSize=OS_16 then
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2)
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
else
a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg2);
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
end;
OS_32,OS_S32:
begin
tmpreg:=getintregister(list,OS_INT);
tmpreg2:=getintregister(list,OS_INT);
{ only complicated references need an extra loadaddr }
if assigned(ref.symbol) or
@ -915,28 +927,42 @@ unit cgcpu;
(reg=ref.index) or
(reg=ref.base) then
begin
tmpreg3:=getintregister(list,OS_INT);
a_loadaddr_ref_reg(list,ref,tmpreg3);
reference_reset_base(usedtmpref,tmpreg3,0);
tmpreg2:=getintregister(list,OS_INT);
a_loadaddr_ref_reg(list,ref,tmpreg2);
reference_reset_base(usedtmpref,tmpreg2,0);
end
else
usedtmpref:=ref;
if target_info.endian=endian_big then
inc(usedtmpref.offset,3);
shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg2,reg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
so.shiftimm:=16;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg,tmpreg2,reg,so));
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
so.shiftimm:=24;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
shifterop_reset(so);so.shiftmode:=SM_LSL;
if ref.alignment=2 then
begin
if target_info.endian=endian_big then
inc(usedtmpref.offset,2);
a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
inc(usedtmpref.offset,dir*2);
a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
so.shiftimm:=16;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
end
else
begin
if target_info.endian=endian_big then
inc(usedtmpref.offset,3);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
so.shiftimm:=8;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
so.shiftimm:=16;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
inc(usedtmpref.offset,dir);
a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
so.shiftimm:=24;
list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
end;
end
else
handle_load_store(list,A_LDR,oppostfix,reg,ref);

View File

@ -2194,48 +2194,66 @@ implementation
tmpreg2 : tregister;
i : longint;
begin
if ref.alignment<>0 then
if ref.alignment in [1,2] then
begin
tmpref:=ref;
{ we take care of the alignment now }
tmpref.alignment:=0;
case FromSize of
OS_16,OS_S16:
begin
{ first load in tmpreg, because the target register }
{ may be used in ref as well }
if target_info.endian=endian_little then
inc(tmpref.offset);
tmpreg:=getintregister(list,OS_8);
a_load_ref_reg(list,OS_8,OS_8,tmpref,tmpreg);
tmpreg:=makeregsize(list,tmpreg,OS_16);
a_op_const_reg(list,OP_SHL,OS_16,8,tmpreg);
if target_info.endian=endian_little then
dec(tmpref.offset)
else
inc(tmpref.offset);
a_load_ref_reg(list,OS_8,OS_16,tmpref,register);
a_op_reg_reg(list,OP_OR,OS_16,tmpreg,register);
end;
if ref.alignment=2 then
a_load_ref_reg(list,fromsize,tosize,tmpref,register)
else
begin
{ first load in tmpreg, because the target register }
{ may be used in ref as well }
if target_info.endian=endian_little then
inc(tmpref.offset);
tmpreg:=getintregister(list,OS_8);
a_load_ref_reg(list,OS_8,OS_8,tmpref,tmpreg);
tmpreg:=makeregsize(list,tmpreg,OS_16);
a_op_const_reg(list,OP_SHL,OS_16,8,tmpreg);
if target_info.endian=endian_little then
dec(tmpref.offset)
else
inc(tmpref.offset);
a_load_ref_reg(list,OS_8,OS_16,tmpref,register);
a_op_reg_reg(list,OP_OR,OS_16,tmpreg,register);
end;
OS_32,OS_S32:
begin
if target_info.endian=endian_little then
inc(tmpref.offset,3);
tmpreg:=getintregister(list,OS_32);
a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg);
tmpreg2:=getintregister(list,OS_32);
for i:=1 to 3 do
begin
a_op_const_reg(list,OP_SHL,OS_32,8,tmpreg);
if target_info.endian=endian_little then
dec(tmpref.offset)
else
inc(tmpref.offset);
a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg2);
a_op_reg_reg(list,OP_OR,OS_32,tmpreg2,tmpreg);
end;
a_load_reg_reg(list,OS_32,OS_32,tmpreg,register);
end
if ref.alignment=2 then
begin
if target_info.endian=endian_little then
inc(tmpref.offset,2);
tmpreg:=getintregister(list,OS_32);
a_load_ref_reg(list,OS_16,OS_32,tmpref,tmpreg);
a_op_const_reg(list,OP_SHL,OS_32,16,tmpreg);
if target_info.endian=endian_little then
dec(tmpref.offset,2)
else
inc(tmpref.offset,2);
a_load_ref_reg(list,OS_16,OS_32,tmpref,register);
a_op_reg_reg(list,OP_OR,OS_32,tmpreg,register);
end
else
begin
if target_info.endian=endian_little then
inc(tmpref.offset,3);
tmpreg:=getintregister(list,OS_32);
a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg);
tmpreg2:=getintregister(list,OS_32);
for i:=1 to 3 do
begin
a_op_const_reg(list,OP_SHL,OS_32,8,tmpreg);
if target_info.endian=endian_little then
dec(tmpref.offset)
else
inc(tmpref.offset);
a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg2);
a_op_reg_reg(list,OP_OR,OS_32,tmpreg2,tmpreg);
end;
a_load_reg_reg(list,OS_32,OS_32,tmpreg,register);
end
else
a_load_ref_reg(list,fromsize,tosize,tmpref,register);
end;

View File

@ -361,6 +361,7 @@ implementation
if (gvs.varspez=vs_const) and
(location.loc=LOC_REFERENCE) then
location.loc:=LOC_CREFERENCE;
location.reference.alignment:=gvs.vardef.alignment;
end;
paravarsym,
localvarsym :
@ -401,7 +402,7 @@ implementation
if (vs.varspez=vs_const) and
(location.loc=LOC_REFERENCE) then
location.loc:=LOC_CREFERENCE;
end;
end;
procsym:
begin
if not assigned(procdef) then

View File

@ -643,22 +643,13 @@ implementation
procedure ttgobj.getlocal(list: TAsmList; size : longint; alignment : shortint; def:tdef;var ref : treference);
begin
{$ifdef arm}
{ for ARM CPU records must be aligned in stack depending of record size }
{ to prevent misaligned error when the record is passed as parameter in registers }
if def.typ=recorddef then
if size>2 then
alignment:=current_settings.alignment.localalignmax
else
alignment:=size;
{$else}
alignment:=used_align(alignment,current_settings.alignment.localalignmin,current_settings.alignment.localalignmax);
{$endif arm}
{ can't use reference_reset_base, because that will let tgobj depend
on cgobj (PFV) }
fillchar(ref,sizeof(ref),0);
ref.base:=current_procinfo.framepointer;
ref.offset:=alloctemp(list,size,alignment,tt_persistent,nil);
ref.alignment:=alignment;
end;

42
tests/test/cg/tpara3.pp Normal file
View File

@ -0,0 +1,42 @@
type
TRec = record
bbb: array[1..8] of byte;
w: word;
end;
TRec2 = packed record
a: array[1..9] of char;
end;
procedure dotest(p: TRec);
var
i: longint;
begin
for i:=1 to 8 do
write(p.bbb[i], ' ');
writeln;
if qword(p.bbb)<>$0102030405060708 then begin
writeln('Test FAILED.');
Halt(1);
end;
end;
procedure dotest2(p: TRec);
var
rr: TRec2;
pp: TRec;
begin
pp:=p;
dotest(pp);
end;
var
b: byte;
p: TRec;
i: longint;
begin
qword(p.bbb):=$0102030405060708;
dotest2(p);
writeln('Test OK.');
end.