From ec943198fd7a6e03577ea8d496c2fe5af7faafd3 Mon Sep 17 00:00:00 2001 From: yury Date: Wed, 16 Apr 2008 23:01:20 +0000 Subject: [PATCH] * 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 - --- .gitattributes | 1 + compiler/arm/cgcpu.pas | 112 +++++++++++++++++++++++++--------------- compiler/cgobj.pas | 88 ++++++++++++++++++------------- compiler/ncgld.pas | 3 +- compiler/tgobj.pas | 11 +--- tests/test/cg/tpara3.pp | 42 +++++++++++++++ 6 files changed, 168 insertions(+), 89 deletions(-) create mode 100644 tests/test/cg/tpara3.pp diff --git a/.gitattributes b/.gitattributes index 5405511ce0..c6a65cb83d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/compiler/arm/cgcpu.pas b/compiler/arm/cgcpu.pas index 2d7f65d902..6a7880cd5f 100644 --- a/compiler/arm/cgcpu.pas +++ b/compiler/arm/cgcpu.pas @@ -791,7 +791,7 @@ unit cgcpu; else InternalError(200308295); end; - if ref.alignment<>0 then + if (ref.alignment in [1,2]) and (ref.alignment0 then + if (ref.alignment in [1,2]) and (ref.alignment0 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; diff --git a/compiler/ncgld.pas b/compiler/ncgld.pas index c346427c47..e5be648e4b 100644 --- a/compiler/ncgld.pas +++ b/compiler/ncgld.pas @@ -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 diff --git a/compiler/tgobj.pas b/compiler/tgobj.pas index f6e3d834cc..5514166f17 100644 --- a/compiler/tgobj.pas +++ b/compiler/tgobj.pas @@ -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; diff --git a/tests/test/cg/tpara3.pp b/tests/test/cg/tpara3.pp new file mode 100644 index 0000000000..c14d05223c --- /dev/null +++ b/tests/test/cg/tpara3.pp @@ -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. \ No newline at end of file