Try to fix crash in loongarch64 compiler

loongarch64 compiler has a specific routine,
  called fixupref that generates some instructions that are
  stored into a tasmlist given as an input parameter.
  This function returns a boolean,
  if the return value is false, the populated list gets
  sometimes discarded.
  This can lead to a later crash, because the unused
  and freed instructions might have been stored
  in live and live_end fields of the reginfo record
  used inside rgobj unit.

  The fix checks if any of the to be discarded instructions
  has been stored inside reginfo records,
  and resets the field in that case.

  The fix might need to be more general,
  because other parts of the compiler,
  like all optimization code, also remove
  instructions...
This commit is contained in:
Pierre Muller 2023-09-22 23:07:37 +02:00
parent 5e6e24ec08
commit e8a03ac8bc

View File

@ -93,7 +93,8 @@ unit cgcpu;
procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
protected
function fixref(list: TAsmList; var ref: treference; mode : tfixref): boolean;
function fixref(list: TAsmList; var ref: treference; mode : tfixref;out tmpreg : tregister): boolean;
procedure ungetregister(r : tregister;list :TAsmList);
procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
end;
@ -326,6 +327,7 @@ implementation
href: treference;
op: TAsmOp;
hlist: TAsmList;
tmpreg : tregister;
const
st_ops: array[boolean,OS_8..OS_INT] of TAsmOp = (
(A_ST_B,A_ST_H,A_ST_W,A_ST_D),
@ -343,18 +345,21 @@ implementation
if stptr_ops[tosize]<>A_NONE then
begin
href:=ref;
if fixref(hlist,href,fr_big) then
if fixref(hlist,href,fr_big,tmpreg) then
begin
list.concatList(hlist);
hlist.free;
list.concat(taicpu.op_reg_ref(stptr_ops[tosize],reg,href));
exit;
end;
end
else
if (tmpreg<>NR_NO) then
ungetregister(tmpreg,hlist);
end;
hlist.Clear;
hlist.free;
href:=ref;
op:=st_ops[fixref(list,href,fr_reg),tosize];
op:=st_ops[fixref(list,href,fr_reg,tmpreg),tosize];
list.concat(taicpu.op_reg_ref(op,reg,href));
end;
@ -367,6 +372,7 @@ implementation
have_done: boolean;
hlist: TAsmList;
samesign: boolean;
tmpreg : tregister;
const
ld_ops: array[boolean,boolean,OS_8..OS_INT] of TAsmOp = (
((A_LD_B,A_LD_H,A_LD_W,A_LD_D),
@ -375,6 +381,7 @@ implementation
(A_LDX_BU,A_LDX_HU,A_LDX_WU,A_LDX_D))
);
begin
tmpreg:=NR_NO;
if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
internalerror(2022111938);
if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
@ -388,7 +395,7 @@ implementation
if (fromsize=OS_S32) then
begin
href:=ref;
if fixref(hlist,href,fr_big) then
if fixref(hlist,href,fr_big,tmpreg) then
begin
hlist.concat(taicpu.op_reg_ref(A_LDPTR_W,reg,href));
have_done:=true;
@ -397,7 +404,7 @@ implementation
else if (fromsize=OS_S64) or (fromsize=OS_64) then
begin
href:=ref;
if fixref(hlist,href,fr_big) then
if fixref(hlist,href,fr_big,tmpreg) then
begin
hlist.concat(taicpu.op_reg_ref(A_LDPTR_D,reg,href));
have_done:=true;
@ -406,9 +413,11 @@ implementation
if not(have_done) then
begin
if (tmpreg<>NR_NO) then
ungetregister(tmpreg,hlist);
hlist.Clear;
href:=ref;
op:=ld_ops[fixref(list,href,fr_reg),fromsize=usizef,usizef];
op:=ld_ops[fixref(list,href,fr_reg,tmpreg),fromsize=usizef,usizef];
list.concat(taicpu.op_reg_ref(op,reg,href));
end
else
@ -489,9 +498,10 @@ implementation
var
href: treference;
l: TAsmLabel;
tmpreg : tregister;
begin
href:=ref;
fixref(list,href,fr_normal);
fixref(list,href,fr_normal,tmpreg);
{ Fixref, so simplely work here. }
if href.offset=0 then
a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
@ -804,6 +814,7 @@ implementation
var
op: TAsmOp;
href: treference;
tmpreg : tregister;
const
fld_ops: array[boolean,boolean] of TAsmOp = (
(A_FLD_D, A_FLD_S),
@ -811,7 +822,7 @@ implementation
);
begin
href:=ref;
op:=fld_ops[fixref(list,href,fr_reg),fromsize=OS_F32];
op:=fld_ops[fixref(list,href,fr_reg,tmpreg),fromsize=OS_F32];
list.concat(taicpu.op_reg_ref(op,reg,href));
if fromsize<>tosize then
a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
@ -822,6 +833,7 @@ implementation
op: TAsmOp;
tmpfreg: TRegister;
href: treference;
tmpreg : tregister;
fst_ops: array[boolean,boolean] of TAsmOp = (
(A_FST_D, A_FST_S),
(A_FSTX_D, A_FSTX_S)
@ -835,7 +847,7 @@ implementation
end;
href:=ref;
op:=fst_ops[fixref(list,href,fr_reg),tosize=OS_F32];
op:=fst_ops[fixref(list,href,fr_reg,tmpreg),tosize=OS_F32];
list.concat(taicpu.op_reg_ref(op,reg,href));
end;
@ -1440,11 +1452,51 @@ implementation
a_op_reg_reg_reg(list,op,size,src1,src2,dst);
end;
function tcgloongarch64.fixref(list: TAsmList; var ref: treference; mode : tfixref): boolean;
procedure tcgloongarch64.ungetregister(r : tregister;list : TAsmList);
var
supreg : tsuperregister;
rt : tregistertype;
live : tai;
function is_in_list(t : tai;hlist : TAsmList) : boolean;
var
current : tai;
begin
result:=false;
if not assigned(t) then
exit;
current:=tai(hlist.first);
while assigned(current) do
begin
if (current=t) then
begin
result:=true;
exit;
end
else
current:=tai(current.next);
end;
end;
begin
if not assigned(list) then
exit;
supreg:=getsupreg(r);
rt:=getregtype(r);
if assigned(rg[rt]) then
begin
if is_in_list(rg[rt].live_start[supreg],list) then
rg[rt].live_start[supreg]:=nil;
if is_in_list(rg[rt].live_end[supreg],list) then
rg[rt].live_end[supreg]:=nil;
end;
end;
function tcgloongarch64.fixref(list: TAsmList; var ref: treference; mode : tfixref; out tmpreg : tregister): boolean;
var
tmpreg: TRegister;
href: treference;
begin
tmpreg:=NR_NO;
if ref.refaddr=addr_reg_12i then
begin
result:=mode=fr_normal;