mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 06:08:16 +02:00
* 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:
parent
24be2c31f7
commit
ec943198fd
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
42
tests/test/cg/tpara3.pp
Normal 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.
|
Loading…
Reference in New Issue
Block a user