+ implemented WebAssembly code generator support for funcref and externref data

types, using new register types R_FUNCREFREGISTER and R_EXTERNREFREGISTER
This commit is contained in:
Nikolay Nikolov 2023-06-07 05:25:57 +03:00
parent e555eddeda
commit 11712658b0
7 changed files with 125 additions and 8 deletions

View File

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

View File

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

View File

@ -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}
);

View File

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

View File

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

View File

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

View File

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