Browse Source

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...
Pierre Muller 1 year ago
parent
commit
e8a03ac8bc
1 changed files with 64 additions and 12 deletions
  1. 64 12
      compiler/loongarch64/cgcpu.pas

+ 64 - 12
compiler/loongarch64/cgcpu.pas

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