mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-09 20:48:12 +02:00
397 lines
11 KiB
ObjectPascal
397 lines
11 KiB
ObjectPascal
{
|
|
Copyright (C) 2019 Dmitry Boyarintsev
|
|
|
|
This unit handles the temporary variables for the WebAssembly
|
|
|
|
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 tgcpu;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
globtype,
|
|
aasmdata,
|
|
cgutils, cpubase,
|
|
symtype,tgobj;
|
|
|
|
type
|
|
|
|
{ TWasmLocal }
|
|
|
|
TWasmLocal = class
|
|
inuse : Boolean;
|
|
noreuse : Boolean;
|
|
index : integer;
|
|
typ : TWasmBasicType;
|
|
next : TWasmLocal; // next in the same basic type
|
|
nextseq : TWasmLocal; // from 0 to max
|
|
constructor create(atype: TWasmBasicType; aindex: integer);
|
|
end;
|
|
|
|
{ TWasmLocalVars }
|
|
|
|
TWasmLocalVars = class
|
|
private
|
|
last: TWasmLocal; // need public?
|
|
public
|
|
locv: array[TWasmBasicType] of TWasmLocal;
|
|
ordered: array of integer;
|
|
first: TWasmLocal; // first in sequence
|
|
varindex: integer;
|
|
constructor Create(astartindex: Integer = 0);
|
|
destructor Destroy; override;
|
|
function alloc(bt: TWasmBasicType): integer;
|
|
function allocnoreuse(bt: TWasmBasicType): integer;
|
|
procedure dealloc(bt: TWasmBasicType; index: integer);
|
|
procedure dealloc(index: integer);
|
|
end;
|
|
|
|
{ ttgwasm }
|
|
|
|
ttgwasm = class(ttgobj)
|
|
private
|
|
procedure updateFirstTemp;
|
|
|
|
procedure allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
|
|
procedure allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
|
|
procedure LocalVarToRef(idx: integer; size: Integer; out ref: treference);
|
|
public
|
|
localvars: TWasmLocalVars;
|
|
|
|
constructor create; override;
|
|
destructor destroy; override;
|
|
procedure setfirsttemp(l : asizeint); override;
|
|
procedure gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); override;
|
|
procedure gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); override;
|
|
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;
|
|
|
|
implementation
|
|
|
|
uses
|
|
verbose,
|
|
cgbase,
|
|
symconst,symtable,symdef,symsym,symcpu,defutil,
|
|
aasmbase,aasmcpu,
|
|
hlcgobj,hlcgcpu, procinfo;
|
|
|
|
function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
|
|
var
|
|
fields, i: Integer;
|
|
wbt_candidate: TWasmBasicType;
|
|
begin
|
|
Result := assigned(def);
|
|
if not Result then
|
|
Exit;
|
|
|
|
if is_wasm_funcref(def) then
|
|
wbt := wbt_funcref
|
|
else if is_wasm_externref(def) then
|
|
wbt := wbt_externref
|
|
else if is_pointer(def) then
|
|
wbt := wbt_i32 // wasm32
|
|
else if is_currency(def) then
|
|
wbt := wbt_i64
|
|
else if is_ordinal(def) then
|
|
begin
|
|
if is_64bit(def) then
|
|
wbt := wbt_i64
|
|
else
|
|
wbt := wbt_i32;
|
|
end
|
|
else if is_real(def) then
|
|
begin
|
|
if is_single(def) then
|
|
wbt := wbt_f32
|
|
else
|
|
wbt := wbt_f64; // real/double/extended
|
|
end
|
|
else if def.typ=recorddef then
|
|
begin
|
|
if not (def.size in [1,2,4,8]) then
|
|
exit(false);
|
|
fields:=0;
|
|
wbt_candidate:=Default(TWasmBasicType);
|
|
for i:=0 to trecorddef(def).symtable.symlist.count-1 do
|
|
begin
|
|
if (tsym(trecorddef(def).symtable.symlist[i]).typ<>fieldvarsym) or
|
|
(sp_static in tsym(trecorddef(def).symtable.symlist[i]).symoptions) then
|
|
continue;
|
|
if assigned(tfieldvarsym(trecorddef(def).symtable.symlist[i]).vardef) then
|
|
begin
|
|
Inc(fields);
|
|
if fields>1 then
|
|
exit(false);
|
|
{ search recursively }
|
|
if not defToWasmBasic(tfieldvarsym(trecorddef(def).symtable.symlist[i]).vardef,wbt_candidate) then
|
|
exit(false);
|
|
end;
|
|
end;
|
|
if fields=1 then
|
|
begin
|
|
wbt:=wbt_candidate;
|
|
result:=true;
|
|
end
|
|
else
|
|
result:=false;
|
|
end
|
|
else if def.typ=arraydef then
|
|
begin
|
|
if (def.size in [1,2,4,8]) and (tarraydef(def).elecount=1) then
|
|
result:=defToWasmBasic(tarraydef(def).elementdef,wbt)
|
|
else
|
|
result:=false;
|
|
end
|
|
else
|
|
Result := false;
|
|
end;
|
|
|
|
{ TWasmLocal }
|
|
|
|
constructor TWasmLocal.create(atype: TWasmBasicType;
|
|
aindex: integer);
|
|
begin
|
|
typ:=atype;
|
|
index:=aindex;
|
|
end;
|
|
|
|
{ TWasmLocalVars }
|
|
|
|
constructor TWasmLocalVars.Create(astartindex: Integer = 0);
|
|
begin
|
|
inherited Create;
|
|
varindex := astartindex;
|
|
end;
|
|
|
|
destructor TWasmLocalVars.Destroy;
|
|
var
|
|
t : TWasmLocal;
|
|
n : TWasmLocal;
|
|
begin
|
|
t := first;
|
|
while Assigned(t) do
|
|
begin
|
|
n:=t;
|
|
t:=t.nextseq;
|
|
n.Free;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
{ ttgwasm }
|
|
|
|
procedure ttgwasm.updateFirstTemp;
|
|
begin
|
|
firsttemp := localvars.varindex;
|
|
if lasttemp<firsttemp then lasttemp := firsttemp;
|
|
end;
|
|
|
|
constructor ttgwasm.create;
|
|
begin
|
|
inherited create;
|
|
localvars:=TWasmLocalVars.Create;
|
|
end;
|
|
|
|
destructor ttgwasm.destroy;
|
|
begin
|
|
localvars.Free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
procedure ttgwasm.setfirsttemp(l: asizeint);
|
|
begin
|
|
firsttemp:=l;
|
|
lasttemp:=l;
|
|
localvars.varindex := l; //?
|
|
end;
|
|
|
|
|
|
procedure ttgwasm.gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference);
|
|
var
|
|
wbt: TWasmBasicType;
|
|
begin
|
|
if temptype=tt_regallocator then
|
|
begin
|
|
if Assigned(def) and defToWasmBasic(def, wbt) then
|
|
allocLocalVarToRef(wbt, ref)
|
|
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;
|
|
|
|
procedure ttgwasm.gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
procedure ttgwasm.ungettemp(list: TAsmList; const ref: treference);
|
|
begin
|
|
if ref.base=NR_LOCAL_STACK_POINTER_REG then
|
|
localvars.dealloc(ref.offset)
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure ttgwasm.allocframepointer(list: TAsmList; out ref: treference);
|
|
begin
|
|
allocLocalVarNoReuseToRef(wbt_i32,ref);
|
|
end;
|
|
|
|
procedure ttgwasm.allocbasepointer(list: TAsmList; out ref: treference);
|
|
begin
|
|
allocLocalVarNoReuseToRef(wbt_i32,ref);
|
|
end;
|
|
|
|
procedure ttgwasm.allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
|
|
var
|
|
idx : integer;
|
|
begin
|
|
idx := localvars.alloc(wbt);
|
|
localVarToRef(idx, 1, ref);
|
|
end;
|
|
|
|
procedure ttgwasm.allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
|
|
var
|
|
idx : integer;
|
|
begin
|
|
idx := localvars.allocnoreuse(wbt);
|
|
localVarToRef(idx, 1, ref);
|
|
end;
|
|
|
|
procedure ttgwasm.localVarToRef(idx: integer; size: integer; out ref: treference);
|
|
begin
|
|
reference_reset_base(ref,NR_LOCAL_STACK_POINTER_REG,idx,ctempposinvalid,size,[]);
|
|
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;
|
|
lc : TWasmLocal;
|
|
t : TWasmLocal;
|
|
begin
|
|
lc := locv[bt];
|
|
t := nil;
|
|
while Assigned(lc) and ((lc.inuse) or (lc.noreuse)) do begin
|
|
t := lc;
|
|
lc := lc.next;
|
|
end;
|
|
if Assigned(lc) then begin
|
|
lc.inuse := true;
|
|
end else begin
|
|
lc := TWasmLocal.Create(bt, varindex);
|
|
if Assigned(t)
|
|
then t.next := lc
|
|
else locv[bt]:=lc;
|
|
lc.inuse:=true;
|
|
inc(varindex);
|
|
|
|
if Assigned(last) then last.nextseq := lc;
|
|
if not Assigned(first) then first := lc;
|
|
last := lc;
|
|
end;
|
|
alloc := lc.index;
|
|
|
|
end;
|
|
|
|
function TWasmLocalVars.allocnoreuse(bt: TWasmBasicType): integer;
|
|
var
|
|
i : integer;
|
|
lc : TWasmLocal;
|
|
t : TWasmLocal;
|
|
begin
|
|
lc := locv[bt];
|
|
t := nil;
|
|
while Assigned(lc) do
|
|
begin
|
|
t := lc;
|
|
lc := lc.next;
|
|
end;
|
|
lc := TWasmLocal.Create(bt, varindex);
|
|
if Assigned(t) then
|
|
t.next := lc
|
|
else
|
|
locv[bt]:=lc;
|
|
lc.inuse:=true;
|
|
lc.noreuse:=true;
|
|
inc(varindex);
|
|
if Assigned(last) then
|
|
last.nextseq := lc;
|
|
if not Assigned(first) then
|
|
first := lc;
|
|
last := lc;
|
|
allocnoreuse := lc.index;
|
|
end;
|
|
|
|
procedure TWasmLocalVars.dealloc(bt: TWasmBasicType; index: integer);
|
|
var
|
|
lc : TWasmLocal;
|
|
begin
|
|
lc := locv[bt];
|
|
while Assigned(lc) and (lc.index <> index) do
|
|
lc := lc.next;
|
|
if Assigned(lc) then lc.inuse := false;
|
|
end;
|
|
|
|
procedure TWasmLocalVars.dealloc(index: integer);
|
|
var
|
|
lc : TWasmLocal;
|
|
begin
|
|
lc := first;
|
|
while Assigned(lc) and (lc.index <> index) do
|
|
lc := lc.nextseq;
|
|
if Assigned(lc) then lc.inuse := false;
|
|
end;
|
|
|
|
|
|
initialization
|
|
tgobjclass:=ttgwasm;
|
|
end.
|