diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas index 3a9adb7d55..8a74b3751f 100644 --- a/compiler/cgbase.pas +++ b/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 diff --git a/compiler/wasm32/cgcpu.pas b/compiler/wasm32/cgcpu.pas index 8aca061b58..64d319ce92 100644 --- a/compiler/wasm32/cgcpu.pas +++ b/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, diff --git a/compiler/wasm32/cpubase.pas b/compiler/wasm32/cpubase.pas index 2c0b8238ba..5ee3efe595 100644 --- a/compiler/wasm32/cpubase.pas +++ b/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} ); diff --git a/compiler/wasm32/hlcgcpu.pas b/compiler/wasm32/hlcgcpu.pas index ea8e530d37..fb4147fd62 100644 --- a/compiler/wasm32/hlcgcpu.pas +++ b/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; diff --git a/compiler/wasm32/rgcpu.pas b/compiler/wasm32/rgcpu.pas index 72b0afdd87..4de2e47a8f 100644 --- a/compiler/wasm32/rgcpu.pas +++ b/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. diff --git a/compiler/wasm32/tgcpu.pas b/compiler/wasm32/tgcpu.pas index bfb06f9ef3..b3dcd1d226 100644 --- a/compiler/wasm32/tgcpu.pas +++ b/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; diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index e98069c40d..ce4d28d8f6 100644 --- a/compiler/x86/aasmcpu.pas +++ b/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;