Browse Source

+ generate proper WebAssembly threadvar access when multithreading is turned on

Nikolay Nikolov 3 years ago
parent
commit
4db653998b
4 changed files with 137 additions and 12 deletions
  1. 22 6
      compiler/ogwasm.pas
  2. 1 1
      compiler/wasm32/cpunode.pas
  3. 48 5
      compiler/wasm32/hlcgcpu.pas
  4. 66 0
      compiler/wasm32/nwasmld.pas

+ 22 - 6
compiler/ogwasm.pas

@@ -673,10 +673,10 @@ implementation
       begin
       begin
         if assigned(asmsym) then
         if assigned(asmsym) then
           begin
           begin
-            if asmsym.typ<>AT_WASM_GLOBAL then
+            if (asmsym.typ<>AT_WASM_GLOBAL) and (asmsym.typ<>AT_TLS) then
               internalerror(2021092706);
               internalerror(2021092706);
             result:=symbolref(asmsym);
             result:=symbolref(asmsym);
-            result.typ:=AT_WASM_GLOBAL;
+            result.typ:=asmsym.typ;
           end
           end
         else
         else
           result:=nil;
           result:=nil;
@@ -1243,7 +1243,7 @@ implementation
         exception_tags_count: Integer = 0;
         exception_tags_count: Integer = 0;
         objsym, ObjSymAlias: TWasmObjSymbol;
         objsym, ObjSymAlias: TWasmObjSymbol;
         cust_sec: TWasmCustomSectionType;
         cust_sec: TWasmCustomSectionType;
-        SegmentFlags: UInt64;
+        SegmentFlags, SymbolFlags: UInt64;
       begin
       begin
         FData:=TWasmObjData(Data);
         FData:=TWasmObjData(Data);
 
 
@@ -1266,6 +1266,8 @@ implementation
                 Inc(import_globals_count)
                 Inc(import_globals_count)
               else
               else
                 Inc(globals_count);
                 Inc(globals_count);
+            if (objsym.typ=AT_TLS) and (ts_wasm_threads in current_settings.targetswitches) then
+              Inc(import_globals_count);
             if IsExternalFunction(objsym) then
             if IsExternalFunction(objsym) then
               Inc(import_functions_count);
               Inc(import_functions_count);
             if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
             if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
@@ -1364,6 +1366,17 @@ implementation
                   WriteByte(FWasmSections[wsiImport],$00)   { const }
                   WriteByte(FWasmSections[wsiImport],$00)   { const }
                 else
                 else
                   WriteByte(FWasmSections[wsiImport],$01);  { var }
                   WriteByte(FWasmSections[wsiImport],$01);  { var }
+              end
+            else if (objsym.typ=AT_TLS) and (ts_wasm_threads in current_settings.targetswitches) then
+              begin
+                objsym.GlobalIndex:=NextGlobalIndex;
+                Inc(NextGlobalIndex);
+                objsym.ExtraData:=nil;
+                WriteName(FWasmSections[wsiImport],'GOT.mem');
+                WriteName(FWasmSections[wsiImport],objsym.Name);
+                WriteByte(FWasmSections[wsiImport],$03);  { global }
+                WriteWasmBasicType(FWasmSections[wsiImport],wbt_i32);  { i32 }
+                WriteByte(FWasmSections[wsiImport],$01);  { var }
               end;
               end;
           end;
           end;
         { import functions }
         { import functions }
@@ -1616,13 +1629,16 @@ implementation
                 Inc(FWasmSymbolTableEntriesCount);
                 Inc(FWasmSymbolTableEntriesCount);
                 WriteByte(FWasmSymbolTable,Ord(SYMTAB_DATA));
                 WriteByte(FWasmSymbolTable,Ord(SYMTAB_DATA));
                 if objsym.bind=AB_GLOBAL then
                 if objsym.bind=AB_GLOBAL then
-                  WriteUleb(FWasmSymbolTable,0)
+                  SymbolFlags:=0
                 else if objsym.bind=AB_LOCAL then
                 else if objsym.bind=AB_LOCAL then
-                  WriteUleb(FWasmSymbolTable,WASM_SYM_BINDING_LOCAL)
+                  SymbolFlags:=WASM_SYM_BINDING_LOCAL
                 else if objsym.bind=AB_EXTERNAL then
                 else if objsym.bind=AB_EXTERNAL then
-                  WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED)
+                  SymbolFlags:=WASM_SYM_UNDEFINED
                 else
                 else
                   internalerror(2021092506);
                   internalerror(2021092506);
+                if (objsym.typ=AT_TLS) and (ts_wasm_threads in current_settings.targetswitches) then
+                  SymbolFlags:=(SymbolFlags and not WASM_SYM_BINDING_LOCAL) or WASM_SYM_TLS;
+                WriteUleb(FWasmSymbolTable,SymbolFlags);
                 WriteName(FWasmSymbolTable,objsym.Name);
                 WriteName(FWasmSymbolTable,objsym.Name);
                 if objsym.bind<>AB_EXTERNAL then
                 if objsym.bind<>AB_EXTERNAL then
                   begin
                   begin

+ 1 - 1
compiler/wasm32/cpunode.pas

@@ -33,7 +33,7 @@ implementation
     ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
     ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
     ncgadd, ncgcal,ncgmat,ncginl,
     ncgadd, ncgcal,ncgmat,ncginl,
     
     
-    nwasmbas,nwasmadd,nwasmcal,nwasmmat,nwasmflw,nwasmcon,nwasmcnv,nwasmset,nwasminl,
+    nwasmbas,nwasmadd,nwasmcal,nwasmmat,nwasmflw,nwasmcon,nwasmcnv,nwasmset,nwasminl,nwasmld,
     { these are not really nodes }
     { these are not really nodes }
     nwasmutil,
     nwasmutil,
     { symtable }
     { symtable }

+ 48 - 5
compiler/wasm32/hlcgcpu.pas

@@ -439,8 +439,24 @@ implementation
       tmpref:=ref;
       tmpref:=ref;
       tmpref.base:=NR_NO;
       tmpref.base:=NR_NO;
       tmpref.index:=NR_NO;
       tmpref.index:=NR_NO;
-      list.Concat(taicpu.op_ref(a_i32_const, tmpref));
-      incstack(list, 1);
+      if tmpref.refaddr=addr_got_tls then
+        begin
+          tmpref.offset:=0;
+          list.Concat(taicpu.op_ref(a_global_get, tmpref));
+          incstack(list, 1);
+          if ref.offset<>0 then
+            begin
+              list.Concat(taicpu.op_const(a_i32_const,ref.offset));
+              incstack(list, 1);
+              list.Concat(taicpu.op_none(a_i32_add));
+              decstack(list, 1);
+            end;
+        end
+      else
+        begin
+          list.Concat(taicpu.op_ref(a_i32_const, tmpref));
+          incstack(list, 1);
+        end;
       if ref.base<>NR_NO then
       if ref.base<>NR_NO then
         begin
         begin
           list.Concat(taicpu.op_reg(a_local_get,ref.base));
           list.Concat(taicpu.op_reg(a_local_get,ref.base));
@@ -1024,6 +1040,8 @@ implementation
 
 
 
 
   function thlcgwasm.prepare_stack_for_ref(list: TAsmList; var ref: treference; dup: boolean): longint;
   function thlcgwasm.prepare_stack_for_ref(list: TAsmList; var ref: treference; dup: boolean): longint;
+    var
+      tmpref: treference;
     begin
     begin
       result:=0;
       result:=0;
       { fake location that indicates the value is already on the stack? }
       { fake location that indicates the value is already on the stack? }
@@ -1037,7 +1055,26 @@ implementation
         end;
         end;
 
 
       // setting up memory offset
       // setting up memory offset
-      if assigned(ref.symbol) and (ref.base=NR_NO) and (ref.index=NR_NO) then
+      if ref.refaddr=addr_got_tls then
+        begin
+          if not assigned(ref.symbol) then
+            internalerror(2022071405);
+          if ref.base<>NR_NO then
+            internalerror(2022071406);
+          if ref.index<>NR_NO then
+            internalerror(2022071407);
+          tmpref:=ref;
+          tmpref.offset:=0;
+          list.Concat(taicpu.op_ref(a_global_get,tmpref));
+          incstack(list,1);
+          if dup then
+            begin
+              list.Concat(taicpu.op_ref(a_global_get,tmpref));
+              incstack(list,1);
+            end;
+          result:=1;
+        end
+      else if assigned(ref.symbol) and (ref.base=NR_NO) and (ref.index=NR_NO) then
         begin
         begin
           list.Concat(taicpu.op_const(a_i32_const,ref.offset));
           list.Concat(taicpu.op_const(a_i32_const,ref.offset));
           incstack(list,1);
           incstack(list,1);
@@ -2296,7 +2333,10 @@ implementation
         exit;
         exit;
       opc:=loadstoreopcref(size,false,ref,finishandval);
       opc:=loadstoreopcref(size,false,ref,finishandval);
 
 
-      list.concat(taicpu.op_ref(opc,ref));
+      if ref.refaddr=addr_got_tls then
+        list.concat(taicpu.op_const(opc,ref.offset))
+      else
+        list.concat(taicpu.op_ref(opc,ref));
       { avoid problems with getting the size of an open array etc }
       { avoid problems with getting the size of an open array etc }
       if wasmAlwayInMem(size) then
       if wasmAlwayInMem(size) then
         size:=ptruinttype;
         size:=ptruinttype;
@@ -2319,7 +2359,10 @@ implementation
         exit;
         exit;
       opc:=loadstoreopcref(size,true,ref,finishandval);
       opc:=loadstoreopcref(size,true,ref,finishandval);
 
 
-      list.concat(taicpu.op_ref(opc,ref));
+      if ref.refaddr=addr_got_tls then
+        list.concat(taicpu.op_const(opc,ref.offset))
+      else
+        list.concat(taicpu.op_ref(opc,ref));
 
 
       { avoid problems with getting the size of an open array etc }
       { avoid problems with getting the size of an open array etc }
       if wasmAlwayInMem(size) then
       if wasmAlwayInMem(size) then

+ 66 - 0
compiler/wasm32/nwasmld.pas

@@ -0,0 +1,66 @@
+{
+    Copyright (c) 1998-2022 by Florian Klaempfl and Nikolay Nikolov
+
+    Generate WebAssembly code for load nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+unit nwasmld;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      nld,ncgld,
+      symsym;
+
+    type
+
+      { twasmloadnode }
+
+      twasmloadnode = class(tcgloadnode)
+      protected
+        procedure generate_threadvar_access(gvs: tstaticvarsym); override;
+      end;
+
+implementation
+
+    uses
+      globtype,globals,
+      aasmbase,aasmdata,
+      cgbase,cgutils,
+      symconst;
+
+    { twasmloadnode }
+
+    procedure twasmloadnode.generate_threadvar_access(gvs: tstaticvarsym);
+      begin
+        if ts_wasm_threads in current_settings.targetswitches then
+          begin
+            if not(vo_is_weak_external in gvs.varoptions) then
+              reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_TLS,use_indirect_symbol(gvs)),0,location.reference.alignment,[])
+            else
+              reference_reset_symbol(location.reference,current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_TLS),0,location.reference.alignment,[]);
+            location.reference.refaddr:=addr_got_tls;
+          end
+        else
+          inherited generate_threadvar_access(gvs);
+      end;
+
+begin
+  cloadnode:=twasmloadnode;
+end.