+ generate proper WebAssembly threadvar access when multithreading is turned on

This commit is contained in:
Nikolay Nikolov 2022-07-14 02:09:12 +03:00
parent 557e823734
commit 4db653998b
4 changed files with 137 additions and 12 deletions

View File

@ -673,10 +673,10 @@ implementation
begin
if assigned(asmsym) then
begin
if asmsym.typ<>AT_WASM_GLOBAL then
if (asmsym.typ<>AT_WASM_GLOBAL) and (asmsym.typ<>AT_TLS) then
internalerror(2021092706);
result:=symbolref(asmsym);
result.typ:=AT_WASM_GLOBAL;
result.typ:=asmsym.typ;
end
else
result:=nil;
@ -1243,7 +1243,7 @@ implementation
exception_tags_count: Integer = 0;
objsym, ObjSymAlias: TWasmObjSymbol;
cust_sec: TWasmCustomSectionType;
SegmentFlags: UInt64;
SegmentFlags, SymbolFlags: UInt64;
begin
FData:=TWasmObjData(Data);
@ -1266,6 +1266,8 @@ implementation
Inc(import_globals_count)
else
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
Inc(import_functions_count);
if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
@ -1364,6 +1366,17 @@ implementation
WriteByte(FWasmSections[wsiImport],$00) { const }
else
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;
{ import functions }
@ -1616,13 +1629,16 @@ implementation
Inc(FWasmSymbolTableEntriesCount);
WriteByte(FWasmSymbolTable,Ord(SYMTAB_DATA));
if objsym.bind=AB_GLOBAL then
WriteUleb(FWasmSymbolTable,0)
SymbolFlags:=0
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
WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED)
SymbolFlags:=WASM_SYM_UNDEFINED
else
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);
if objsym.bind<>AB_EXTERNAL then
begin

View File

@ -33,7 +33,7 @@ implementation
ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
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 }
nwasmutil,
{ symtable }

View File

@ -439,8 +439,24 @@ implementation
tmpref:=ref;
tmpref.base:=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
begin
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;
var
tmpref: treference;
begin
result:=0;
{ fake location that indicates the value is already on the stack? }
@ -1037,7 +1055,26 @@ implementation
end;
// 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
list.Concat(taicpu.op_const(a_i32_const,ref.offset));
incstack(list,1);
@ -2296,7 +2333,10 @@ implementation
exit;
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 }
if wasmAlwayInMem(size) then
size:=ptruinttype;
@ -2319,7 +2359,10 @@ implementation
exit;
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 }
if wasmAlwayInMem(size) then

View File

@ -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.