tgcpu.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. {
  2. Copyright (C) 2019 Dmitry Boyarintsev
  3. This unit handles the temporary variables for the WebAssembly
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit tgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmdata,
  23. cgutils, cpubase,
  24. symtype,tgobj;
  25. type
  26. { TWasmLocal }
  27. TWasmLocal = class
  28. inuse : Boolean;
  29. noreuse : Boolean;
  30. index : integer;
  31. typ : TWasmBasicType;
  32. next : TWasmLocal; // next in the same basic type
  33. nextseq : TWasmLocal; // from 0 to max
  34. constructor create(atype: TWasmBasicType; aindex: integer);
  35. end;
  36. { TWasmLocalVars }
  37. TWasmLocalVars = class
  38. private
  39. last: TWasmLocal; // need public?
  40. public
  41. locv: array[TWasmBasicType] of TWasmLocal;
  42. ordered: array of integer;
  43. first: TWasmLocal; // first in sequence
  44. varindex: integer;
  45. constructor Create(astartindex: Integer = 0);
  46. destructor Destroy; override;
  47. function alloc(bt: TWasmBasicType): integer;
  48. function allocnoreuse(bt: TWasmBasicType): integer;
  49. procedure dealloc(bt: TWasmBasicType; index: integer);
  50. procedure dealloc(index: integer);
  51. end;
  52. { ttgwasm }
  53. ttgwasm = class(ttgobj)
  54. private
  55. procedure updateFirstTemp;
  56. procedure allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
  57. procedure allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
  58. procedure LocalVarToRef(idx: integer; size: Integer; out ref: treference);
  59. public
  60. localvars: TWasmLocalVars;
  61. constructor create; override;
  62. destructor destroy; override;
  63. procedure setfirsttemp(l : asizeint); override;
  64. procedure gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); override;
  65. procedure gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); override;
  66. procedure ungettemp(list: TAsmList; const ref : treference); override;
  67. procedure allocframepointer(list: TAsmList; out ref: treference);
  68. procedure allocbasepointer(list: TAsmList; out ref: treference);
  69. procedure getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref : treference); override;
  70. end;
  71. function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
  72. implementation
  73. uses
  74. verbose,
  75. cgbase,
  76. symconst,symtable,symdef,symsym,symcpu,defutil,
  77. aasmbase,aasmcpu,
  78. hlcgobj,hlcgcpu, procinfo;
  79. function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
  80. var
  81. fields, i: Integer;
  82. wbt_candidate: TWasmBasicType;
  83. begin
  84. Result := assigned(def);
  85. if not Result then
  86. Exit;
  87. if is_wasm_funcref(def) then
  88. wbt := wbt_funcref
  89. else if is_wasm_externref(def) then
  90. wbt := wbt_externref
  91. else if is_pointer(def) then
  92. wbt := wbt_i32 // wasm32
  93. else if is_currency(def) then
  94. wbt := wbt_i64
  95. else if is_ordinal(def) then
  96. begin
  97. if is_64bit(def) then
  98. wbt := wbt_i64
  99. else
  100. wbt := wbt_i32;
  101. end
  102. else if is_real(def) then
  103. begin
  104. if is_single(def) then
  105. wbt := wbt_f32
  106. else
  107. wbt := wbt_f64; // real/double/extended
  108. end
  109. else if def.typ=recorddef then
  110. begin
  111. if not (def.size in [1,2,4,8]) then
  112. exit(false);
  113. fields:=0;
  114. wbt_candidate:=Default(TWasmBasicType);
  115. for i:=0 to trecorddef(def).symtable.symlist.count-1 do
  116. begin
  117. if (tsym(trecorddef(def).symtable.symlist[i]).typ<>fieldvarsym) or
  118. (sp_static in tsym(trecorddef(def).symtable.symlist[i]).symoptions) then
  119. continue;
  120. if assigned(tfieldvarsym(trecorddef(def).symtable.symlist[i]).vardef) then
  121. begin
  122. Inc(fields);
  123. if fields>1 then
  124. exit(false);
  125. { search recursively }
  126. if not defToWasmBasic(tfieldvarsym(trecorddef(def).symtable.symlist[i]).vardef,wbt_candidate) then
  127. exit(false);
  128. end;
  129. end;
  130. if fields=1 then
  131. begin
  132. wbt:=wbt_candidate;
  133. result:=true;
  134. end
  135. else
  136. result:=false;
  137. end
  138. else if def.typ=arraydef then
  139. begin
  140. if (def.size in [1,2,4,8]) and (tarraydef(def).elecount=1) then
  141. result:=defToWasmBasic(tarraydef(def).elementdef,wbt)
  142. else
  143. result:=false;
  144. end
  145. else
  146. Result := false;
  147. end;
  148. { TWasmLocal }
  149. constructor TWasmLocal.create(atype: TWasmBasicType;
  150. aindex: integer);
  151. begin
  152. typ:=atype;
  153. index:=aindex;
  154. end;
  155. { TWasmLocalVars }
  156. constructor TWasmLocalVars.Create(astartindex: Integer = 0);
  157. begin
  158. inherited Create;
  159. varindex := astartindex;
  160. end;
  161. destructor TWasmLocalVars.Destroy;
  162. var
  163. t : TWasmLocal;
  164. n : TWasmLocal;
  165. begin
  166. t := first;
  167. while Assigned(t) do
  168. begin
  169. n:=t;
  170. t:=t.nextseq;
  171. n.Free;
  172. end;
  173. inherited Destroy;
  174. end;
  175. { ttgwasm }
  176. procedure ttgwasm.updateFirstTemp;
  177. begin
  178. firsttemp := localvars.varindex;
  179. if lasttemp<firsttemp then lasttemp := firsttemp;
  180. end;
  181. constructor ttgwasm.create;
  182. begin
  183. inherited create;
  184. localvars:=TWasmLocalVars.Create;
  185. end;
  186. destructor ttgwasm.destroy;
  187. begin
  188. localvars.Free;
  189. inherited destroy;
  190. end;
  191. procedure ttgwasm.setfirsttemp(l: asizeint);
  192. begin
  193. firsttemp:=l;
  194. lasttemp:=l;
  195. localvars.varindex := l; //?
  196. end;
  197. procedure ttgwasm.gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference);
  198. var
  199. wbt: TWasmBasicType;
  200. begin
  201. if temptype=tt_regallocator then
  202. begin
  203. if Assigned(def) and defToWasmBasic(def, wbt) then
  204. allocLocalVarToRef(wbt, ref)
  205. else
  206. internalerror(2020121801);
  207. end
  208. else if Assigned(def) and is_wasm_reference_type(def) then
  209. begin
  210. if defToWasmBasic(def, wbt) then
  211. allocLocalVarToRef(wbt, ref)
  212. else
  213. internalerror(2023060701);
  214. end
  215. else
  216. inherited;
  217. end;
  218. procedure ttgwasm.gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
  219. begin
  220. inherited;
  221. end;
  222. procedure ttgwasm.ungettemp(list: TAsmList; const ref: treference);
  223. begin
  224. if ref.base=NR_LOCAL_STACK_POINTER_REG then
  225. localvars.dealloc(ref.offset)
  226. else
  227. inherited;
  228. end;
  229. procedure ttgwasm.allocframepointer(list: TAsmList; out ref: treference);
  230. begin
  231. allocLocalVarNoReuseToRef(wbt_i32,ref);
  232. end;
  233. procedure ttgwasm.allocbasepointer(list: TAsmList; out ref: treference);
  234. begin
  235. allocLocalVarNoReuseToRef(wbt_i32,ref);
  236. end;
  237. procedure ttgwasm.allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
  238. var
  239. idx : integer;
  240. begin
  241. idx := localvars.alloc(wbt);
  242. localVarToRef(idx, 1, ref);
  243. end;
  244. procedure ttgwasm.allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
  245. var
  246. idx : integer;
  247. begin
  248. idx := localvars.allocnoreuse(wbt);
  249. localVarToRef(idx, 1, ref);
  250. end;
  251. procedure ttgwasm.localVarToRef(idx: integer; size: integer; out ref: treference);
  252. begin
  253. reference_reset_base(ref,NR_LOCAL_STACK_POINTER_REG,idx,ctempposinvalid,size,[]);
  254. updateFirstTemp;
  255. end;
  256. procedure ttgwasm.getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref : treference);
  257. var
  258. wbt: TWasmBasicType;
  259. begin
  260. if is_wasm_reference_type(def) then
  261. begin
  262. if defToWasmBasic(def, wbt) then
  263. allocLocalVarToRef(wbt, ref)
  264. else
  265. internalerror(2023060703);
  266. end
  267. else
  268. inherited;
  269. end;
  270. function TWasmLocalVars.alloc(bt: TWasmBasicType): integer;
  271. var
  272. i : integer;
  273. lc : TWasmLocal;
  274. t : TWasmLocal;
  275. begin
  276. lc := locv[bt];
  277. t := nil;
  278. while Assigned(lc) and ((lc.inuse) or (lc.noreuse)) do begin
  279. t := lc;
  280. lc := lc.next;
  281. end;
  282. if Assigned(lc) then begin
  283. lc.inuse := true;
  284. end else begin
  285. lc := TWasmLocal.Create(bt, varindex);
  286. if Assigned(t)
  287. then t.next := lc
  288. else locv[bt]:=lc;
  289. lc.inuse:=true;
  290. inc(varindex);
  291. if Assigned(last) then last.nextseq := lc;
  292. if not Assigned(first) then first := lc;
  293. last := lc;
  294. end;
  295. alloc := lc.index;
  296. end;
  297. function TWasmLocalVars.allocnoreuse(bt: TWasmBasicType): integer;
  298. var
  299. i : integer;
  300. lc : TWasmLocal;
  301. t : TWasmLocal;
  302. begin
  303. lc := locv[bt];
  304. t := nil;
  305. while Assigned(lc) do
  306. begin
  307. t := lc;
  308. lc := lc.next;
  309. end;
  310. lc := TWasmLocal.Create(bt, varindex);
  311. if Assigned(t) then
  312. t.next := lc
  313. else
  314. locv[bt]:=lc;
  315. lc.inuse:=true;
  316. lc.noreuse:=true;
  317. inc(varindex);
  318. if Assigned(last) then
  319. last.nextseq := lc;
  320. if not Assigned(first) then
  321. first := lc;
  322. last := lc;
  323. allocnoreuse := lc.index;
  324. end;
  325. procedure TWasmLocalVars.dealloc(bt: TWasmBasicType; index: integer);
  326. var
  327. lc : TWasmLocal;
  328. begin
  329. lc := locv[bt];
  330. while Assigned(lc) and (lc.index <> index) do
  331. lc := lc.next;
  332. if Assigned(lc) then lc.inuse := false;
  333. end;
  334. procedure TWasmLocalVars.dealloc(index: integer);
  335. var
  336. lc : TWasmLocal;
  337. begin
  338. lc := first;
  339. while Assigned(lc) and (lc.index <> index) do
  340. lc := lc.nextseq;
  341. if Assigned(lc) then lc.inuse := false;
  342. end;
  343. initialization
  344. tgobjclass:=ttgwasm;
  345. end.