{ 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 localsfirsttemp, localslasttemp: longint; 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 localsfirsttemp := localvars.varindex; if localslasttemp 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.