Browse Source

+ implemented WebAssembly code generator support for funcref and externref data
types, using new register types R_FUNCREFREGISTER and R_EXTERNREFREGISTER

Nikolay Nikolov 2 years ago
parent
commit
11712658b0

+ 5 - 1
compiler/cgbase.pas

@@ -241,7 +241,11 @@ interface
         { used on llvm for tracking metadata (every unique metadata has its own base register) }
         { used on llvm for tracking metadata (every unique metadata has its own base register) }
         R_METADATAREGISTER,{ = 8 }
         R_METADATAREGISTER,{ = 8 }
         { optional MAC16 (16 bit multiply-accumulate) registers on Xtensa }
         { optional MAC16 (16 bit multiply-accumulate) registers on Xtensa }
-        R_MAC16REGISTER    { = 9 }
+        R_MAC16REGISTER,   { = 9 }
+        { WebAssembly externref }
+        R_EXTERNREFREGISTER, { = 10 }
+        { WebAssembly funcref }
+        R_FUNCREFREGISTER  { = 11 }
 
 
         { do not add more than 16 elements (ifdef by cpu type if needed)
         { do not add more than 16 elements (ifdef by cpu type if needed)
           so we can store this in one nibble and pack TRegister
           so we can store this in one nibble and pack TRegister

+ 20 - 0
compiler/wasm32/cgcpu.pas

@@ -41,6 +41,8 @@ interface
         function  getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
         function  getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
         function  getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
         function  getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
         function  getaddressregister(list:TAsmList):Tregister;override;
         function  getaddressregister(list:TAsmList):Tregister;override;
+        function  getfuncrefregister(list:TAsmList):Tregister;
+        function  getexternrefregister(list:TAsmList):Tregister;
         procedure do_register_allocation(list:TAsmList;headertai:tai);override;
         procedure do_register_allocation(list:TAsmList;headertai:tai);override;
       end;
       end;
 
 
@@ -73,6 +75,10 @@ implementation
           [RS_R0],first_fpu_imreg,[]);
           [RS_R0],first_fpu_imreg,[]);
         rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
         rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
           [RS_R0],first_mm_imreg,[]);
           [RS_R0],first_mm_imreg,[]);
+        rg[R_FUNCREFREGISTER]:=Trgcpu.create(R_FUNCREFREGISTER,R_SUBNONE,
+          [RS_R0],first_funcref_imreg,[]);
+        rg[R_EXTERNREFREGISTER]:=Trgcpu.create(R_EXTERNREFREGISTER,R_SUBNONE,
+          [RS_R0],first_externref_imreg,[]);
       end;
       end;
 
 
 
 
@@ -81,6 +87,8 @@ implementation
         rg[R_INTREGISTER].free;
         rg[R_INTREGISTER].free;
         rg[R_FPUREGISTER].free;
         rg[R_FPUREGISTER].free;
         rg[R_MMREGISTER].free;
         rg[R_MMREGISTER].free;
+        rg[R_FUNCREFREGISTER].free;
+        rg[R_EXTERNREFREGISTER].free;
         inherited done_register_allocators;
         inherited done_register_allocators;
       end;
       end;
 
 
@@ -112,6 +120,18 @@ implementation
       end;
       end;
 
 
 
 
+    function  tcgwasm.getfuncrefregister(list:TAsmList):Tregister;
+      begin
+        result:=rg[R_FUNCREFREGISTER].getregister(list,R_SUBNONE);
+      end;
+
+
+    function  tcgwasm.getexternrefregister(list:TAsmList):Tregister;
+      begin
+        result:=rg[R_EXTERNREFREGISTER].getregister(list,R_SUBNONE);
+      end;
+
+
     procedure tcgwasm.do_register_allocation(list:TAsmList;headertai:tai);
     procedure tcgwasm.do_register_allocation(list:TAsmList;headertai:tai);
       begin
       begin
         { We only run the "register allocation" once for an arbitrary allocator,
         { We only run the "register allocation" once for an arbitrary allocator,

+ 6 - 0
compiler/wasm32/cpubase.pas

@@ -230,6 +230,12 @@ uses
       { MM Super register first and last }
       { MM Super register first and last }
       first_mm_imreg     = 4;
       first_mm_imreg     = 4;
 
 
+      { funcref Super register first and last }
+      first_funcref_imreg     = 4;
+
+      { externref Super register first and last }
+      first_externref_imreg     = 4;
+
       regnumber_table : array[tregisterindex] of tregister = (
       regnumber_table : array[tregisterindex] of tregister = (
         {$i rwasmnum.inc}
         {$i rwasmnum.inc}
       );
       );

+ 41 - 3
compiler/wasm32/hlcgcpu.pas

@@ -65,6 +65,8 @@ uses
       procedure decstack(list : TAsmList;slots: longint);
       procedure decstack(list : TAsmList;slots: longint);
 
 
       class function def2regtyp(def: tdef): tregistertype; override;
       class function def2regtyp(def: tdef): tregistertype; override;
+      function getintregister(list:TAsmList;size:tdef):Tregister;override;
+      function getregisterfordef(list: TAsmList;size:tdef):Tregister;override;
 
 
       procedure a_load_const_cgpara(list : TAsmList;tosize : tdef;a : tcgint;const cgpara : TCGPara);override;
       procedure a_load_const_cgpara(list : TAsmList;tosize : tdef;a : tcgint;const cgpara : TCGPara);override;
 
 
@@ -256,7 +258,7 @@ implementation
     defutil,cpupi,
     defutil,cpupi,
     aasmtai,aasmcpu,
     aasmtai,aasmcpu,
     symtable,symcpu,
     symtable,symcpu,
-    procinfo,cpuinfo,cgcpu,tgobj,tgcpu,paramgr;
+    procinfo,cpuinfo,cgobj,cgcpu,tgobj,tgcpu,paramgr;
 
 
   const
   const
     TOpCG2IAsmOp : array[topcg] of TAsmOp=(
     TOpCG2IAsmOp : array[topcg] of TAsmOp=(
@@ -364,13 +366,39 @@ implementation
 
 
   class function thlcgwasm.def2regtyp(def: tdef): tregistertype;
   class function thlcgwasm.def2regtyp(def: tdef): tregistertype;
     begin
     begin
-      if (def.typ=recorddef) and (def.size in [4,8]) and (trecorddef(def).contains_float_field) then
+      if is_wasm_externref(def) then
+        result:=R_EXTERNREFREGISTER
+      else if is_wasm_funcref(def) then
+        result:=R_FUNCREFREGISTER
+      else if (def.typ=recorddef) and (def.size in [4,8]) and (trecorddef(def).contains_float_field) then
         result:=R_FPUREGISTER
         result:=R_FPUREGISTER
       else
       else
         result:=inherited;
         result:=inherited;
     end;
     end;
 
 
 
 
+  function thlcgwasm.getintregister(list:TAsmList;size:tdef):Tregister;
+    begin
+      if is_wasm_reference_type(size) then
+        internalerror(2023060702)
+      else
+        result:=inherited;
+    end;
+
+
+  function thlcgwasm.getregisterfordef(list: TAsmList;size:tdef):Tregister;
+    begin
+      case def2regtyp(size) of
+        R_EXTERNREFREGISTER:
+          result:=TCgWasm(cg).getexternrefregister(list);
+        R_FUNCREFREGISTER:
+          result:=TCgWasm(cg).getfuncrefregister(list);
+        else
+          result:=inherited;
+      end;
+    end;
+
+
   procedure thlcgwasm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
   procedure thlcgwasm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
     begin
     begin
       tosize:=get_para_push_size(tosize);
       tosize:=get_para_push_size(tosize);
@@ -1024,7 +1052,17 @@ implementation
               end;
               end;
             else
             else
               internalerror(2011010302);
               internalerror(2011010302);
-          end
+          end;
+        R_FUNCREFREGISTER:
+          begin
+            list.concat(taicpu.op_none(a_ref_null_funcref));
+            incstack(list,1);
+          end;
+        R_EXTERNREFREGISTER:
+          begin
+            list.concat(taicpu.op_none(a_ref_null_externref));
+            incstack(list,1);
+          end;
         else
         else
           internalerror(2011010301);
           internalerror(2011010301);
       end;
       end;

+ 28 - 2
compiler/wasm32/rgcpu.pas

@@ -54,7 +54,7 @@ implementation
       globtype,globals,
       globtype,globals,
       cgobj,
       cgobj,
       tgobj,
       tgobj,
-      symtype,symdef,symcpu;
+      symtype,symdef,symconst,symcpu;
 
 
     { trgcpu }
     { trgcpu }
 
 
@@ -326,7 +326,9 @@ implementation
         spill_temps : tspilltemps;
         spill_temps : tspilltemps;
         templist : TAsmList;
         templist : TAsmList;
         intrg,
         intrg,
-        fprg     : trgcpu;
+        fprg,
+        frrg,
+        errg     : trgcpu;
         p,q      : tai;
         p,q      : tai;
         size     : longint;
         size     : longint;
 
 
@@ -340,6 +342,7 @@ implementation
         pidx    : integer;
         pidx    : integer;
         t: treftemppos;
         t: treftemppos;
         def: tdef;
         def: tdef;
+        wasmfuncreftype: tprocvardef;
 
 
       begin
       begin
         { Since there are no actual registers, we simply spill everything. We
         { Since there are no actual registers, we simply spill everything. We
@@ -350,9 +353,13 @@ implementation
         { get references to all register allocators }
         { get references to all register allocators }
         intrg:=trgcpu(cg.rg[R_INTREGISTER]);
         intrg:=trgcpu(cg.rg[R_INTREGISTER]);
         fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
         fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
+        frrg:=trgcpu(cg.rg[R_FUNCREFREGISTER]);
+        errg:=trgcpu(cg.rg[R_EXTERNREFREGISTER]);
         { determine the live ranges of all registers }
         { determine the live ranges of all registers }
         intrg.insert_regalloc_info_all(list);
         intrg.insert_regalloc_info_all(list);
         fprg.insert_regalloc_info_all(list);
         fprg.insert_regalloc_info_all(list);
+        frrg.insert_regalloc_info_all(list);
+        errg.insert_regalloc_info_all(list);
         { Don't do the actual allocation when -sr is passed }
         { Don't do the actual allocation when -sr is passed }
         if (cs_no_regalloc in current_settings.globalswitches) then
         if (cs_no_regalloc in current_settings.globalswitches) then
           exit;
           exit;
@@ -361,8 +368,13 @@ implementation
         { allocate room to store the virtual register -> temp mapping }
         { allocate room to store the virtual register -> temp mapping }
         spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
         spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
         spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
         spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
+        spill_temps[R_FUNCREFREGISTER]:=allocmem(sizeof(treference)*frrg.maxreg);
+        spill_temps[R_EXTERNREFREGISTER]:=allocmem(sizeof(treference)*errg.maxreg);
         { List to insert temp allocations into }
         { List to insert temp allocations into }
         templist:=TAsmList.create;
         templist:=TAsmList.create;
+        {  }
+        wasmfuncreftype:=cprocvardef.create(normal_function_level,true);
+        include(wasmfuncreftype.procoptions,po_wasm_funcref);
         { allocate/replace all registers }
         { allocate/replace all registers }
         p:=headertai;
         p:=headertai;
         insbefore := nil;
         insbefore := nil;
@@ -408,6 +420,16 @@ implementation
                           else
                           else
                             internalerror(2020120804);
                             internalerror(2020120804);
                         end;
                         end;
+                      R_FUNCREFREGISTER:
+                        begin
+                          size:=0;
+                          def:=wasmfuncreftype;
+                        end;
+                      R_EXTERNREFREGISTER:
+                        begin
+                          size:=0;
+                          def:=wasmvoidexternreftype;
+                        end;
                       else
                       else
                         internalerror(2010122912);
                         internalerror(2010122912);
                     end;
                     end;
@@ -445,7 +467,11 @@ implementation
           list.insertListBefore(nil, templist);
           list.insertListBefore(nil, templist);
         freemem(spill_temps[R_INTREGISTER]);
         freemem(spill_temps[R_INTREGISTER]);
         freemem(spill_temps[R_FPUREGISTER]);
         freemem(spill_temps[R_FPUREGISTER]);
+        freemem(spill_temps[R_FUNCREFREGISTER]);
+        freemem(spill_temps[R_EXTERNREFREGISTER]);
         templist.free;
         templist.free;
+        { Not needed anymore }
+        wasmfuncreftype.owner.deletedef(wasmfuncreftype);
       end;
       end;
 
 
 end.
 end.

+ 23 - 0
compiler/wasm32/tgcpu.pas

@@ -83,6 +83,7 @@ unit tgcpu;
          procedure ungettemp(list: TAsmList; const ref : treference); override;
          procedure ungettemp(list: TAsmList; const ref : treference); override;
          procedure allocframepointer(list: TAsmList; out ref: treference);
          procedure allocframepointer(list: TAsmList; out ref: treference);
          procedure allocbasepointer(list: TAsmList; out ref: treference);
          procedure allocbasepointer(list: TAsmList; out ref: treference);
+         procedure getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref : treference); override;
        end;
        end;
 
 
     function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
     function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
@@ -239,6 +240,13 @@ unit tgcpu;
             else
             else
               internalerror(2020121801);
               internalerror(2020121801);
           end
           end
+        else if Assigned(def) and is_wasm_reference_type(def) then
+          begin
+            if defToWasmBasic(def, wbt) then
+              allocLocalVarToRef(wbt, ref)
+            else
+              internalerror(2023060701);
+          end
         else
         else
           inherited;
           inherited;
       end;
       end;
@@ -288,6 +296,21 @@ unit tgcpu;
         updateFirstTemp;
         updateFirstTemp;
       end;
       end;
 
 
+    procedure ttgwasm.getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref : treference);
+      var
+        wbt: TWasmBasicType;
+      begin
+        if is_wasm_reference_type(def) then
+          begin
+            if defToWasmBasic(def, wbt) then
+              allocLocalVarToRef(wbt, ref)
+            else
+              internalerror(2023060703);
+          end
+        else
+          inherited;
+      end;
+
     function TWasmLocalVars.alloc(bt: TWasmBasicType): integer;
     function TWasmLocalVars.alloc(bt: TWasmBasicType): integer;
       var
       var
         i : integer;
         i : integer;

+ 2 - 2
compiler/x86/aasmcpu.pas

@@ -2490,9 +2490,9 @@ implementation
           (0, 1, 2, 3, 6, 7, 5, 4);
           (0, 1, 2, 3, 6, 7, 5, 4);
         maxsupreg: array[tregistertype] of tsuperregister=
         maxsupreg: array[tregistertype] of tsuperregister=
 {$ifdef x86_64}
 {$ifdef x86_64}
-          (0, 16, 9, 8, 32, 32, 8, 0, 0, 0);
+          (0, 16, 9, 8, 32, 32, 8, 0, 0, 0, 0, 0);
 {$else x86_64}
 {$else x86_64}
-          (0,  8, 9, 8,  8, 32, 8, 0, 0, 0);
+          (0,  8, 9, 8,  8, 32, 8, 0, 0, 0, 0, 0);
 {$endif x86_64}
 {$endif x86_64}
       var
       var
         rs: tsuperregister;
         rs: tsuperregister;