diff options
-rw-r--r-- | compiler/arm/cgcpu.pas | 26 | ||||
-rw-r--r-- | tests/tbs/tb613.pp | 85 |
2 files changed, 104 insertions, 7 deletions
diff --git a/compiler/arm/cgcpu.pas b/compiler/arm/cgcpu.pas index a3a60597be..7642587e86 100644 --- a/compiler/arm/cgcpu.pas +++ b/compiler/arm/cgcpu.pas @@ -2339,31 +2339,43 @@ unit cgcpu; var ref : treference; l : TAsmLabel; + regs : tcpuregisterset; + r: byte; begin if (cs_create_pic in current_settings.moduleswitches) and (pi_needs_got in current_procinfo.flags) and (tf_pic_uses_got in target_info.flags) then begin + { Procedure parametrs are not initialized at this stage. + Before GOT initialization code, allocate registers used for procedure parameters + to prevent usage of these registers for temp operations in later stages of code + generation. } + regs:=rg[R_INTREGISTER].used_in_proc; + for r:=RS_R0 to RS_R3 do + if r in regs then + a_reg_alloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE)); + { Allocate scratch register R12 and use it for GOT calculations directly. + Otherwise the init code can be distorted in later stages of code generation. } + a_reg_alloc(list,NR_R12); + reference_reset(ref,4); current_asmdata.getglobaldatalabel(l); cg.a_label(current_procinfo.aktlocaldata,l); ref.symbol:=l; ref.base:=NR_PC; ref.symboldata:=current_procinfo.aktlocaldata.last; - a_reg_alloc(list,NR_R12); list.concat(Taicpu.op_reg_ref(A_LDR,NR_R12,ref)); current_asmdata.getaddrlabel(l); current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_32bit,l,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),-8)); cg.a_label(list,l); - { - It is needed to perform GOT calculations using the scratch register R12 - and then MOV the result to the GOT register. Otherwise the register allocator will use - register R0 as temp to perform calculations in case if a procedure uses all available registers. - It leads to corruption of R0 which is normally holds a value of the first procedure parameter. - } list.concat(Taicpu.op_reg_reg_reg(A_ADD,NR_R12,NR_PC,NR_R12)); list.concat(Taicpu.op_reg_reg(A_MOV,current_procinfo.got,NR_R12)); + + { Deallocate registers } a_reg_dealloc(list,NR_R12); + for r:=RS_R3 downto RS_R0 do + if r in regs then + a_reg_dealloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE)); end; end; diff --git a/tests/tbs/tb613.pp b/tests/tbs/tb613.pp new file mode 100644 index 0000000000..4ff70685c2 --- /dev/null +++ b/tests/tbs/tb613.pp @@ -0,0 +1,85 @@ +{$mode objfpc} +{$PIC+} + +{ + Test for proper initialization of GOT register. +} + +const + BufSize = 128*1024; + +var + gvar: longint; + +procedure check(c, e: longint); +begin + if c <> e then begin + writeln('ERROR. Result: ', c, ' Expected: ', e); + Halt(1); + end; +end; + +function test101(p1, p2: longint): longint; +begin + result:=gvar+p1+p2; +end; + +function test102(p1, p2: longint): longint; +var + Buffer: array[0..BufSize] of byte; +begin + Buffer[0]:=0; + result:=gvar+p1+p2+Buffer[0]; +end; + +function test103(p1, p2: longint): longint; +var + a, j: longint; +begin + a:=0; + for j:=1 to 1 do begin + a:=a + j; + a:=a - j; + end; + result:=gvar+p1+p2+a; +end; + +function test111(p1, p2: longint): longint; +var + i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15: longint; + a, j: longint; +begin + i1:=1;i2:=2;i3:=3;i4:=4;i5:=5;i6:=6;i7:=7;i8:=8;i9:=9;i10:=10;i11:=11;i12:=12;i13:=13;i14:=14;i15:=15; + a:=0; + for j:=1 to 1 do begin + a:=a + (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15); + a:=a - (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15); + end; + result:=gvar+p1+p2+a; +end; + +function test112(p1, p2: longint): longint; +var + i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15: longint; + a, j: longint; + Buffer: array[0..BufSize] of byte; +begin + i1:=1;i2:=2;i3:=3;i4:=4;i5:=5;i6:=6;i7:=7;i8:=8;i9:=9;i10:=10;i11:=11;i12:=12;i13:=13;i14:=14;i15:=15; + a:=0; + Buffer[0]:=0; + for j:=1 to 1 do begin + a:=a + (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15); + a:=a - (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15); + a:=a + Buffer[0]; + end; + result:=gvar+p1+p2+a; +end; + +begin + gvar:=100; + check(test101(10, 20), 130); + check(test102(20, 30), 150); + check(test103(30, 40), 170); + check(test111(110, 20), 230); + check(test112(120, 30), 250); +end. |