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) }
         R_METADATAREGISTER,{ = 8 }
         { 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)
           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  getfpuregister(list:TAsmList;size:Tcgsize):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;
       end;
 
@@ -73,6 +75,10 @@ implementation
           [RS_R0],first_fpu_imreg,[]);
         rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
           [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;
 
 
@@ -81,6 +87,8 @@ implementation
         rg[R_INTREGISTER].free;
         rg[R_FPUREGISTER].free;
         rg[R_MMREGISTER].free;
+        rg[R_FUNCREFREGISTER].free;
+        rg[R_EXTERNREFREGISTER].free;
         inherited done_register_allocators;
       end;
 
@@ -112,6 +120,18 @@ implementation
       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);
       begin
         { 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 }
       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 = (
         {$i rwasmnum.inc}
       );

+ 41 - 3
compiler/wasm32/hlcgcpu.pas

@@ -65,6 +65,8 @@ uses
       procedure decstack(list : TAsmList;slots: longint);
 
       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;
 
@@ -256,7 +258,7 @@ implementation
     defutil,cpupi,
     aasmtai,aasmcpu,
     symtable,symcpu,
-    procinfo,cpuinfo,cgcpu,tgobj,tgcpu,paramgr;
+    procinfo,cpuinfo,cgobj,cgcpu,tgobj,tgcpu,paramgr;
 
   const
     TOpCG2IAsmOp : array[topcg] of TAsmOp=(
@@ -364,13 +366,39 @@ implementation
 
   class function thlcgwasm.def2regtyp(def: tdef): tregistertype;
     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
       else
         result:=inherited;
     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);
     begin
       tosize:=get_para_push_size(tosize);
@@ -1024,7 +1052,17 @@ implementation
               end;
             else
               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
           internalerror(2011010301);
       end;

+ 28 - 2
compiler/wasm32/rgcpu.pas

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

+ 23 - 0
compiler/wasm32/tgcpu.pas

@@ -83,6 +83,7 @@ unit tgcpu;
          procedure ungettemp(list: TAsmList; const ref : treference); override;
          procedure allocframepointer(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;
 
     function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
@@ -239,6 +240,13 @@ unit tgcpu;
             else
               internalerror(2020121801);
           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
           inherited;
       end;
@@ -288,6 +296,21 @@ unit tgcpu;
         updateFirstTemp;
       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;
       var
         i : integer;

+ 2 - 2
compiler/x86/aasmcpu.pas

@@ -2490,9 +2490,9 @@ implementation
           (0, 1, 2, 3, 6, 7, 5, 4);
         maxsupreg: array[tregistertype] of tsuperregister=
 {$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}
-          (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}
       var
         rs: tsuperregister;