rawasmtext.pas 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  1. {
  2. Copyright (c) 1998-2008 by Carl Eric Codere and Peter Vreman
  3. Copyright (c) 2024 by Nikolay Nikolov
  4. Does the parsing for the WebAssembly styled inline assembler.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit rawasmtext;
  19. {$i fpcdefs.inc}
  20. Interface
  21. uses
  22. cclasses,
  23. globtype,
  24. rasm,rawasm,
  25. aasmbase,cpubase;
  26. type
  27. tasmtoken = (
  28. AS_NONE,AS_LPAREN,AS_RPAREN,AS_ID,AS_END,AS_OPCODE,AS_INTNUM,
  29. AS_REALNUM,AS_STRING,AS_PARAM,AS_RESULT,AS_THEN,AS_ELSE,AS_TYPE,AS_VALTYPE
  30. );
  31. tasmkeyword = string[10];
  32. const
  33. token2str : array[tasmtoken] of tasmkeyword=(
  34. '','(',')','identifier','end','opcode','integer','float','string',
  35. 'param','result','then','else','type','valtype');
  36. type
  37. { twasmreader }
  38. twasmreader = class(tasmreader)
  39. private
  40. actwasmbasictype: TWasmBasicType;
  41. actasmpattern_origcase: string;
  42. actasmtoken : tasmtoken;
  43. prevasmtoken : tasmtoken;
  44. actinttoken : aint;
  45. actfloattoken : double;
  46. procedure SetupTables;
  47. procedure GetToken;
  48. function consume(t : tasmtoken):boolean;
  49. function is_asmopcode(const s: string):boolean;
  50. function is_valtype(const s: string):boolean;
  51. procedure HandleInstruction;
  52. procedure HandleFoldedInstruction;
  53. function HandlePlainInstruction: TWasmInstruction;
  54. procedure HandleBlockInstruction;
  55. public
  56. function Assemble: tlinkedlist;override;
  57. end;
  58. Implementation
  59. uses
  60. { helpers }
  61. cutils,
  62. { global }
  63. globals,verbose,
  64. systems,
  65. { aasm }
  66. cpuinfo,aasmtai,aasmdata,aasmcpu,
  67. { symtable }
  68. symconst,symbase,symtype,symsym,symtable,symdef,symutil,symcpu,
  69. { parser }
  70. scanner,pbase,
  71. procinfo,
  72. rabase,rautils,
  73. cgbase,cgutils,cgobj,
  74. hlcgobj,hlcgcpu,
  75. { wasm }
  76. itcpuwasm
  77. ;
  78. {*****************************************************************************
  79. twasmreader
  80. *****************************************************************************}
  81. procedure twasmreader.SetupTables;
  82. var
  83. i: TAsmOp;
  84. begin
  85. iasmops:=TFPHashList.create;
  86. for i:=firstop to lastop do
  87. if wasm_op2str[i]<>'end' then
  88. iasmops.Add(wasm_op2str[i],Pointer(PtrInt(i)));
  89. end;
  90. procedure twasmreader.GetToken;
  91. var
  92. has_sign, is_hex, is_float: Boolean;
  93. function GetIntToken: aint;
  94. var
  95. s: string;
  96. u64: UInt64;
  97. begin
  98. s:=actasmpattern;
  99. if has_sign and (s[1]='-') then
  100. begin
  101. delete(s,1,1);
  102. if is_hex then
  103. begin
  104. delete(s,1,2);
  105. Val('$'+s,u64);
  106. end
  107. else
  108. Val(s,u64);
  109. {$push} {$R-}{$Q-}
  110. result:=aint(-u64);
  111. {$pop}
  112. end
  113. else
  114. begin
  115. if has_sign then
  116. delete(s,1,1);
  117. if is_hex then
  118. begin
  119. delete(s,1,2);
  120. Val('$'+s,u64);
  121. end
  122. else
  123. Val(s,u64);
  124. result:=aint(u64);
  125. end;
  126. end;
  127. function GetFloatToken: double;
  128. var
  129. s: string;
  130. begin
  131. s:=actasmpattern;
  132. if is_hex then
  133. begin
  134. { TODO: parse hex floats }
  135. internalerror(2024071501);
  136. end
  137. else
  138. Val(s,result);
  139. end;
  140. var
  141. len: Integer;
  142. tmpS: string;
  143. tmpI, tmpCode: Integer;
  144. begin
  145. c:=scanner.c;
  146. { save old token and reset new token }
  147. prevasmtoken:=actasmtoken;
  148. actasmtoken:=AS_NONE;
  149. { reset }
  150. actasmpattern:='';
  151. { while space, tab, new line or comment, continue scan... }
  152. while c in [' ',#9,#13,#10] do
  153. begin
  154. c:=current_scanner.asmgetchar;
  155. case c of
  156. ';':
  157. begin
  158. c:=current_scanner.asmgetchar;
  159. case c of
  160. { ;; comment until end of line }
  161. ';':
  162. begin
  163. { skip until end of line }
  164. repeat
  165. c:=current_scanner.asmgetchar;
  166. until c in [#13,#10];
  167. end;
  168. else
  169. current_scanner.illegal_char(c);
  170. end;
  171. end;
  172. '(':
  173. begin
  174. current_scanner.gettokenpos;
  175. c:=current_scanner.asmgetchar;
  176. case c of
  177. { (; block comment ;) }
  178. ';':
  179. begin
  180. { skip until ;) }
  181. repeat
  182. c:=current_scanner.asmgetchar;
  183. if c=';' then
  184. begin
  185. c:=current_scanner.asmgetchar;
  186. if c=')' then
  187. begin
  188. c:=current_scanner.asmgetchar;
  189. break;
  190. end;
  191. end;
  192. until false;
  193. end;
  194. else
  195. begin
  196. actasmtoken:=AS_LPAREN;
  197. exit;
  198. end;
  199. end;
  200. end;
  201. end;
  202. end;
  203. current_scanner.gettokenpos;
  204. case c of
  205. ')':
  206. begin
  207. c:=current_scanner.asmgetchar;
  208. actasmtoken:=AS_RPAREN;
  209. end;
  210. '$','a'..'z','A'..'Z':
  211. begin
  212. len:=0;
  213. while c in ['A'..'Z','a'..'z','0'..'9',
  214. '!','#','$','%','&','''','*','+','-','.','/',
  215. ':','<','=','>','?','@','\','^','_','`','|','~'] do
  216. begin
  217. inc(len);
  218. actasmpattern[len]:=c;
  219. c:=current_scanner.asmgetchar;
  220. end;
  221. actasmpattern[0]:=chr(len);
  222. actasmpattern_origcase:=actasmpattern;
  223. if actasmpattern[1]='$' then
  224. actasmtoken:=AS_ID
  225. else if is_asmopcode(actasmpattern) or
  226. is_valtype(actasmpattern) then
  227. exit
  228. else if upper(actasmpattern) = 'END' then
  229. begin
  230. uppervar(actasmpattern);
  231. actasmtoken:=AS_END;
  232. exit;
  233. end
  234. else
  235. begin
  236. message1(asmr_e_unknown_opcode,actasmpattern);
  237. actasmtoken:=AS_NONE;
  238. end;
  239. end;
  240. '0'..'9','+','-':
  241. begin
  242. len:=0;
  243. has_sign:=false;
  244. is_hex:=false;
  245. is_float:=false;
  246. if c in ['+','-'] then
  247. begin
  248. has_sign:=true;
  249. inc(len);
  250. actasmpattern[len]:=c;
  251. c:=current_scanner.asmgetchar;
  252. end;
  253. if c='0' then
  254. begin
  255. inc(len);
  256. actasmpattern[len]:=c;
  257. c:=current_scanner.asmgetchar;
  258. if c='x' then
  259. begin
  260. is_hex:=true;
  261. inc(len);
  262. actasmpattern[len]:=c;
  263. c:=current_scanner.asmgetchar;
  264. end;
  265. end;
  266. if is_hex then
  267. begin
  268. while c in ['0'..'9','a'..'f','A'..'F'] do
  269. begin
  270. inc(len);
  271. actasmpattern[len]:=c;
  272. c:=current_scanner.asmgetchar;
  273. end;
  274. end
  275. else
  276. begin
  277. while c in ['0'..'9'] do
  278. begin
  279. inc(len);
  280. actasmpattern[len]:=c;
  281. c:=current_scanner.asmgetchar;
  282. end;
  283. end;
  284. if c='.' then
  285. begin
  286. is_float:=true;
  287. inc(len);
  288. actasmpattern[len]:=c;
  289. c:=current_scanner.asmgetchar;
  290. { parse the fractional part }
  291. if is_hex then
  292. begin
  293. while c in ['0'..'9','a'..'f','A'..'F'] do
  294. begin
  295. inc(len);
  296. actasmpattern[len]:=c;
  297. c:=current_scanner.asmgetchar;
  298. end;
  299. end
  300. else
  301. begin
  302. while c in ['0'..'9'] do
  303. begin
  304. inc(len);
  305. actasmpattern[len]:=c;
  306. c:=current_scanner.asmgetchar;
  307. end;
  308. end;
  309. end;
  310. if (is_hex and (c in ['p','P'])) or
  311. ((not is_hex) and (c in ['e','E'])) then
  312. begin
  313. inc(len);
  314. actasmpattern[len]:=c;
  315. c:=current_scanner.asmgetchar;
  316. if c in ['+','-'] then
  317. begin
  318. inc(len);
  319. actasmpattern[len]:=c;
  320. c:=current_scanner.asmgetchar;
  321. end;
  322. while c in ['0'..'9'] do
  323. begin
  324. inc(len);
  325. actasmpattern[len]:=c;
  326. c:=current_scanner.asmgetchar;
  327. end;
  328. end;
  329. actasmpattern[0]:=chr(len);
  330. if is_float then
  331. begin
  332. actasmtoken:=AS_REALNUM;
  333. actfloattoken:=GetFloatToken;
  334. end
  335. else
  336. begin
  337. actasmtoken:=AS_INTNUM;
  338. actinttoken:=GetIntToken;
  339. end;
  340. end;
  341. '"':
  342. begin
  343. actasmpattern:='';
  344. repeat
  345. c:=current_scanner.asmgetchar;
  346. case c of
  347. '\' :
  348. begin
  349. c:=current_scanner.asmgetchar;
  350. case c of
  351. 't':
  352. begin
  353. actasmpattern:=actasmpattern+#9;
  354. c:=current_scanner.asmgetchar;
  355. end;
  356. 'n':
  357. begin
  358. actasmpattern:=actasmpattern+#10;
  359. c:=current_scanner.asmgetchar;
  360. end;
  361. 'r':
  362. begin
  363. actasmpattern:=actasmpattern+#13;
  364. c:=current_scanner.asmgetchar;
  365. end;
  366. '"':
  367. begin
  368. actasmpattern:=actasmpattern+'"';
  369. c:=current_scanner.asmgetchar;
  370. end;
  371. '''':
  372. begin
  373. actasmpattern:=actasmpattern+'''';
  374. c:=current_scanner.asmgetchar;
  375. end;
  376. '\':
  377. begin
  378. actasmpattern:=actasmpattern+'\';
  379. c:=current_scanner.asmgetchar;
  380. end;
  381. 'u':
  382. begin
  383. tmpS:='';
  384. c:=current_scanner.asmgetchar;
  385. while c in ['0'..'9','a'..'f','A'..'F'] do
  386. begin
  387. tmpS:=tmpS+c;
  388. c:=current_scanner.asmgetchar;
  389. end;
  390. if tmpS<>'' then
  391. begin
  392. Val('$'+tmpS,tmpI,tmpCode);
  393. if (tmpI<$D800) or ((tmpI>=$E000) and (tmpI<$110000)) then
  394. begin
  395. if tmpI<=$7F then
  396. actasmpattern:=actasmpattern+Chr(tmpI)
  397. else if tmpI<=$7FF then
  398. actasmpattern:=actasmpattern+
  399. Chr(%11000000 or (tmpI shr 6))+
  400. Chr(%10000000 or (tmpI and $3F))
  401. else if tmpI<=$FFFF then
  402. actasmpattern:=actasmpattern+
  403. Chr(%11100000 or (tmpI shr 12))+
  404. Chr(%10000000 or ((tmpI shr 6) and $3F))+
  405. Chr(%10000000 or (tmpI and $3F))
  406. else
  407. actasmpattern:=actasmpattern+
  408. Chr(%11110000 or (tmpI shr 18))+
  409. Chr(%10000000 or ((tmpI shr 12) and $3F))+
  410. Chr(%10000000 or ((tmpI shr 6) and $3F))+
  411. Chr(%10000000 or (tmpI and $3F))
  412. end
  413. else
  414. Message1(asmr_e_escape_seq_ignored,'u'+tmpS);
  415. end
  416. else
  417. Message1(asmr_e_escape_seq_ignored,'u');
  418. end;
  419. '0'..'9','a'..'f','A'..'F':
  420. begin
  421. tmpS:=c;
  422. c:=current_scanner.asmgetchar;
  423. if c in ['0'..'9','a'..'f','A'..'F'] then
  424. begin
  425. tmpS:=tmpS+c;
  426. c:=current_scanner.asmgetchar;
  427. Val('$'+tmpS,tmpI,tmpCode);
  428. actasmpattern:=actasmpattern+Chr(tmpI);
  429. end
  430. else
  431. begin
  432. Message1(asmr_e_escape_seq_ignored,tmpS+c);
  433. c:=current_scanner.asmgetchar;
  434. end;
  435. end;
  436. else
  437. begin
  438. Message1(asmr_e_escape_seq_ignored,c);
  439. c:=current_scanner.asmgetchar;
  440. end;
  441. end;
  442. end;
  443. '"' :
  444. begin
  445. c:=current_scanner.asmgetchar;
  446. break;
  447. end;
  448. #10,#13:
  449. Message(scan_f_string_exceeds_line);
  450. #0..#9,#11,#12,#14..#31,#127:
  451. current_scanner.illegal_char(c);
  452. else
  453. actasmpattern:=actasmpattern+c;
  454. end;
  455. until false;
  456. actasmtoken:=AS_STRING;
  457. exit;
  458. end;
  459. else
  460. current_scanner.illegal_char(c);
  461. end;
  462. end;
  463. function twasmreader.consume(t: tasmtoken): boolean;
  464. begin
  465. Consume:=true;
  466. if t<>actasmtoken then
  467. begin
  468. Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]);
  469. Consume:=false;
  470. end;
  471. repeat
  472. gettoken;
  473. until actasmtoken<>AS_NONE;
  474. end;
  475. function twasmreader.is_asmopcode(const s: string): boolean;
  476. begin
  477. actopcode:=tasmop(PtrUInt(iasmops.Find(s)));
  478. if actopcode<>A_NONE then
  479. begin
  480. actasmtoken:=AS_OPCODE;
  481. is_asmopcode:=true;
  482. end
  483. else
  484. is_asmopcode:=false;
  485. end;
  486. function twasmreader.is_valtype(const s: string): boolean;
  487. begin
  488. actwasmbasictype:=wbt_Unknown;
  489. case s of
  490. 'i32':
  491. actwasmbasictype:=wbt_i32;
  492. 'i64':
  493. actwasmbasictype:=wbt_i64;
  494. 'f32':
  495. actwasmbasictype:=wbt_f32;
  496. 'f64':
  497. actwasmbasictype:=wbt_f64;
  498. 'funcref':
  499. actwasmbasictype:=wbt_funcref;
  500. 'externref':
  501. actwasmbasictype:=wbt_externref;
  502. 'v128':
  503. actwasmbasictype:=wbt_v128;
  504. end;
  505. if actwasmbasictype<>wbt_Unknown then
  506. begin
  507. actasmtoken:=AS_VALTYPE;
  508. is_valtype:=true;
  509. end
  510. else
  511. is_valtype:=false;
  512. end;
  513. procedure twasmreader.HandleInstruction;
  514. var
  515. instr: TWasmInstruction;
  516. begin
  517. case actasmtoken of
  518. AS_LPAREN:
  519. begin
  520. Consume(AS_LPAREN);
  521. HandleFoldedInstruction;
  522. end;
  523. AS_OPCODE:
  524. begin
  525. case actopcode of
  526. a_block,
  527. a_loop,
  528. a_if:
  529. HandleBlockInstruction;
  530. else
  531. begin
  532. instr:=HandlePlainInstruction;
  533. instr.ConcatInstruction(curlist);
  534. end;
  535. end;
  536. end;
  537. else
  538. internalerror(2024071603);
  539. end;
  540. end;
  541. procedure twasmreader.HandleFoldedInstruction;
  542. var
  543. HasLabel, HasType, HasParam, HasResult, HasInstructions,
  544. HasThen, HasElse: Boolean;
  545. instr: TWasmInstruction;
  546. tmpS: string;
  547. begin
  548. instr:=nil;
  549. //Consume(AS_LPAREN);
  550. case actasmtoken of
  551. AS_OPCODE:
  552. begin
  553. case actopcode of
  554. a_block,
  555. a_loop,
  556. a_if:
  557. begin
  558. Consume(AS_OPCODE);
  559. HasType:=False;
  560. HasParam:=False;
  561. HasResult:=False;
  562. HasInstructions:=False;
  563. HasThen:=False;
  564. HasElse:=False;
  565. instr:=TWasmInstruction.create(TWasmOperand);
  566. instr.opcode:=actopcode;
  567. HasLabel:=False;
  568. if actasmtoken=AS_ID then
  569. begin
  570. Consume(AS_ID);
  571. HasLabel:=True;
  572. end;
  573. repeat
  574. case actasmtoken of
  575. AS_LPAREN:
  576. begin
  577. Consume(AS_LPAREN);
  578. case actasmtoken of
  579. AS_TYPE:
  580. begin
  581. if HasElse or HasThen or HasInstructions or HasResult or HasParam or HasType then
  582. begin
  583. {TODO: error}
  584. end;
  585. Consume(AS_TYPE);
  586. //TODO: consume u32 or id
  587. Consume(actasmtoken);
  588. Consume(AS_RPAREN);
  589. end;
  590. AS_PARAM:
  591. begin
  592. if HasElse or HasThen or HasInstructions or HasResult then
  593. begin
  594. {TODO: error}
  595. end;
  596. Consume(AS_PARAM);
  597. if actasmtoken=AS_ID then
  598. begin
  599. tmpS:=actasmpattern;
  600. Consume(AS_ID);
  601. if actasmtoken=AS_VALTYPE then
  602. instr.AddParam(actasmpattern,actwasmbasictype);
  603. Consume(AS_VALTYPE);
  604. end
  605. else
  606. begin
  607. while actasmtoken<>AS_RPAREN do
  608. begin
  609. if actasmtoken=AS_VALTYPE then
  610. instr.AddParam('',actwasmbasictype);
  611. Consume(AS_VALTYPE);
  612. end;
  613. end;
  614. Consume(AS_RPAREN);
  615. end;
  616. AS_RESULT:
  617. begin
  618. if HasElse or HasThen or HasInstructions then
  619. begin
  620. {TODO: error}
  621. end;
  622. Consume(AS_RESULT);
  623. while actasmtoken<>AS_RPAREN do
  624. begin
  625. if actasmtoken=AS_VALTYPE then
  626. instr.AddResult(actwasmbasictype);
  627. Consume(AS_VALTYPE);
  628. end;
  629. Consume(AS_RPAREN);
  630. end;
  631. AS_THEN:
  632. begin
  633. if instr.opcode<>a_if then
  634. {error!};
  635. Consume(AS_THEN);
  636. HasThen:=True;
  637. while actasmtoken<>AS_RPAREN do
  638. HandleInstruction;
  639. Consume(AS_RPAREN);
  640. end;
  641. AS_ELSE:
  642. begin
  643. if instr.opcode<>a_if then
  644. {error!};
  645. Consume(AS_ELSE);
  646. HasElse:=True;
  647. while actasmtoken<>AS_RPAREN do
  648. HandleInstruction;
  649. Consume(AS_RPAREN);
  650. end;
  651. else
  652. begin
  653. HasInstructions:=True;
  654. HandleFoldedInstruction;
  655. end;
  656. end;
  657. end;
  658. else
  659. {todo: error};
  660. end;
  661. until false;
  662. end;
  663. else
  664. begin
  665. instr:=HandlePlainInstruction;
  666. while actasmtoken<>AS_RPAREN do
  667. begin
  668. Consume(AS_LPAREN);
  669. HandleFoldedInstruction;
  670. end;
  671. instr.ConcatInstruction(curlist);
  672. instr.Free;
  673. instr:=nil;
  674. Consume(AS_RPAREN);
  675. end;
  676. end;
  677. end;
  678. else
  679. {error}
  680. end;
  681. end;
  682. function twasmreader.HandlePlainInstruction: TWasmInstruction;
  683. var
  684. srsym: tsym;
  685. srsymtable: TSymtable;
  686. globsym: TWasmGlobalAsmSymbol;
  687. begin
  688. result:=nil;
  689. case actasmtoken of
  690. AS_OPCODE:
  691. begin
  692. result:=TWasmInstruction.create(TWasmOperand);
  693. result.opcode:=actopcode;
  694. Consume(AS_OPCODE);
  695. case result.opcode of
  696. { instructions, which require 0 operands }
  697. a_nop,
  698. a_unreachable,
  699. a_return,
  700. a_ref_is_null,
  701. a_drop,
  702. a_memory_size,
  703. a_memory_grow,
  704. a_memory_fill,
  705. a_memory_copy,
  706. a_i32_clz,a_i32_ctz,a_i32_popcnt,a_i32_add,a_i32_sub,a_i32_mul,a_i32_div_s,a_i32_div_u,a_i32_rem_s,a_i32_rem_u,a_i32_and,a_i32_or,a_i32_xor,a_i32_shl,a_i32_shr_s,a_i32_shr_u,a_i32_rotl,a_i32_rotr,
  707. a_i64_clz,a_i64_ctz,a_i64_popcnt,a_i64_add,a_i64_sub,a_i64_mul,a_i64_div_s,a_i64_div_u,a_i64_rem_s,a_i64_rem_u,a_i64_and,a_i64_or,a_i64_xor,a_i64_shl,a_i64_shr_s,a_i64_shr_u,a_i64_rotl,a_i64_rotr,
  708. a_f32_abs,a_f32_neg,a_f32_ceil,a_f32_floor,a_f32_trunc,a_f32_nearest,a_f32_sqrt,a_f32_add,a_f32_sub,a_f32_mul,a_f32_div,a_f32_min,a_f32_max,a_f32_copysign,
  709. a_f64_abs,a_f64_neg,a_f64_ceil,a_f64_floor,a_f64_trunc,a_f64_nearest,a_f64_sqrt,a_f64_add,a_f64_sub,a_f64_mul,a_f64_div,a_f64_min,a_f64_max,a_f64_copysign,
  710. a_i32_eqz,a_i32_eq,a_i32_ne,a_i32_lt_s,a_i32_lt_u,a_i32_gt_s,a_i32_gt_u,a_i32_le_s,a_i32_le_u,a_i32_ge_s,a_i32_ge_u,
  711. a_i64_eqz,a_i64_eq,a_i64_ne,a_i64_lt_s,a_i64_lt_u,a_i64_gt_s,a_i64_gt_u,a_i64_le_s,a_i64_le_u,a_i64_ge_s,a_i64_ge_u,
  712. a_f32_eq,a_f32_ne,a_f32_lt,a_f32_gt,a_f32_le,a_f32_ge,
  713. a_f64_eq,a_f64_ne,a_f64_lt,a_f64_gt,a_f64_le,a_f64_ge,
  714. a_i32_wrap_i64,
  715. a_i32_trunc_f32_s,
  716. a_i32_trunc_f32_u,
  717. a_i32_trunc_f64_s,
  718. a_i32_trunc_f64_u,
  719. a_i32_trunc_sat_f32_s,
  720. a_i32_trunc_sat_f32_u,
  721. a_i32_trunc_sat_f64_s,
  722. a_i32_trunc_sat_f64_u,
  723. a_i64_extend_i32_s,
  724. a_i64_extend_i32_u,
  725. a_i64_trunc_f32_s,
  726. a_i64_trunc_f32_u,
  727. a_i64_trunc_f64_s,
  728. a_i64_trunc_f64_u,
  729. a_i64_trunc_sat_f32_s,
  730. a_i64_trunc_sat_f32_u,
  731. a_i64_trunc_sat_f64_u,
  732. a_i64_trunc_sat_f64_s,
  733. a_f32_convert_i32_s,
  734. a_f32_convert_i32_u,
  735. a_f32_convert_i64_s,
  736. a_f32_convert_i64_u,
  737. a_f32_demote_f64,
  738. a_f64_convert_i32_s,
  739. a_f64_convert_i32_u,
  740. a_f64_convert_i64_s,
  741. a_f64_convert_i64_u,
  742. a_f64_promote_f32,
  743. a_i32_reinterpret_f32,
  744. a_i64_reinterpret_f64,
  745. a_f32_reinterpret_i32,
  746. a_f64_reinterpret_i64,
  747. a_i32_extend8_s,
  748. a_i32_extend16_s,
  749. a_i64_extend8_s,
  750. a_i64_extend16_s,
  751. a_i64_extend32_s,
  752. a_atomic_fence:
  753. ;
  754. { instructions with an integer const operand }
  755. a_i32_const,
  756. a_i64_const:
  757. begin
  758. if actasmtoken=AS_INTNUM then
  759. begin
  760. result.ops:=1;
  761. result.operands[1].opr.typ:=OPR_CONSTANT;
  762. result.operands[1].opr.val:=actinttoken;
  763. Consume(AS_INTNUM);
  764. end
  765. else
  766. begin
  767. { error: expected integer }
  768. result.Free;
  769. result:=nil;
  770. Consume(AS_INTNUM);
  771. end;
  772. end;
  773. { instructions with a float const operand }
  774. a_f32_const,
  775. a_f64_const:
  776. begin
  777. case actasmtoken of
  778. AS_INTNUM:
  779. begin
  780. result.ops:=1;
  781. result.operands[1].opr.typ:=OPR_FLOATCONSTANT;
  782. result.operands[1].opr.floatval:=actinttoken;
  783. Consume(AS_INTNUM);
  784. end;
  785. AS_REALNUM:
  786. begin
  787. result.ops:=1;
  788. result.operands[1].opr.typ:=OPR_FLOATCONSTANT;
  789. result.operands[1].opr.floatval:=actfloattoken;
  790. Consume(AS_REALNUM);
  791. end;
  792. else
  793. begin
  794. { error: expected real }
  795. result.Free;
  796. result:=nil;
  797. Consume(AS_REALNUM);
  798. end;
  799. end;
  800. end;
  801. { instructions with an optional memarg operand }
  802. a_i32_load,
  803. a_i64_load,
  804. a_f32_load,
  805. a_f64_load,
  806. a_i32_load8_s,
  807. a_i32_load8_u,
  808. a_i32_load16_s,
  809. a_i32_load16_u,
  810. a_i64_load8_s,
  811. a_i64_load8_u,
  812. a_i64_load16_s,
  813. a_i64_load16_u,
  814. a_i64_load32_s,
  815. a_i64_load32_u,
  816. a_i32_store,
  817. a_i64_store,
  818. a_f32_store,
  819. a_f64_store,
  820. a_i32_store8,
  821. a_i32_store16,
  822. a_i64_store8,
  823. a_i64_store16,
  824. a_i64_store32,
  825. a_memory_atomic_notify,
  826. a_memory_atomic_wait32,
  827. a_memory_atomic_wait64,
  828. a_i32_atomic_load,
  829. a_i64_atomic_load,
  830. a_i32_atomic_load8_u,
  831. a_i32_atomic_load16_u,
  832. a_i64_atomic_load8_u,
  833. a_i64_atomic_load16_u,
  834. a_i64_atomic_load32_u,
  835. a_i32_atomic_store,
  836. a_i64_atomic_store,
  837. a_i32_atomic_store8,
  838. a_i32_atomic_store16,
  839. a_i64_atomic_store8,
  840. a_i64_atomic_store16,
  841. a_i64_atomic_store32,
  842. a_i32_atomic_rmw_add,
  843. a_i64_atomic_rmw_add,
  844. a_i32_atomic_rmw8_add_u,
  845. a_i32_atomic_rmw16_add_u,
  846. a_i64_atomic_rmw8_add_u,
  847. a_i64_atomic_rmw16_add_u,
  848. a_i64_atomic_rmw32_add_u,
  849. a_i32_atomic_rmw_sub,
  850. a_i64_atomic_rmw_sub,
  851. a_i32_atomic_rmw8_sub_u,
  852. a_i32_atomic_rmw16_sub_u,
  853. a_i64_atomic_rmw8_sub_u,
  854. a_i64_atomic_rmw16_sub_u,
  855. a_i64_atomic_rmw32_sub_u,
  856. a_i32_atomic_rmw_and,
  857. a_i64_atomic_rmw_and,
  858. a_i32_atomic_rmw8_and_u,
  859. a_i32_atomic_rmw16_and_u,
  860. a_i64_atomic_rmw8_and_u,
  861. a_i64_atomic_rmw16_and_u,
  862. a_i64_atomic_rmw32_and_u,
  863. a_i32_atomic_rmw_or,
  864. a_i64_atomic_rmw_or,
  865. a_i32_atomic_rmw8_or_u,
  866. a_i32_atomic_rmw16_or_u,
  867. a_i64_atomic_rmw8_or_u,
  868. a_i64_atomic_rmw16_or_u,
  869. a_i64_atomic_rmw32_or_u,
  870. a_i32_atomic_rmw_xor,
  871. a_i64_atomic_rmw_xor,
  872. a_i32_atomic_rmw8_xor_u,
  873. a_i32_atomic_rmw16_xor_u,
  874. a_i64_atomic_rmw8_xor_u,
  875. a_i64_atomic_rmw16_xor_u,
  876. a_i64_atomic_rmw32_xor_u,
  877. a_i32_atomic_rmw_xchg,
  878. a_i64_atomic_rmw_xchg,
  879. a_i32_atomic_rmw8_xchg_u,
  880. a_i32_atomic_rmw16_xchg_u,
  881. a_i64_atomic_rmw8_xchg_u,
  882. a_i64_atomic_rmw16_xchg_u,
  883. a_i64_atomic_rmw32_xchg_u,
  884. a_i32_atomic_rmw_cmpxchg,
  885. a_i64_atomic_rmw_cmpxchg,
  886. a_i32_atomic_rmw8_cmpxchg_u,
  887. a_i32_atomic_rmw16_cmpxchg_u,
  888. a_i64_atomic_rmw8_cmpxchg_u,
  889. a_i64_atomic_rmw16_cmpxchg_u,
  890. a_i64_atomic_rmw32_cmpxchg_u:
  891. begin
  892. { TODO: parse the optional memarg operand }
  893. result.ops:=1;
  894. result.operands[1].opr.typ:=OPR_CONSTANT;
  895. result.operands[1].opr.val:=0;
  896. end;
  897. { instructions that take a local variable parameter (or index) }
  898. a_local_get,
  899. a_local_set,
  900. a_local_tee:
  901. case actasmtoken of
  902. AS_INTNUM:
  903. begin
  904. result.ops:=1;
  905. result.operands[1].opr.typ:=OPR_CONSTANT;
  906. result.operands[1].opr.val:=actinttoken;
  907. Consume(AS_INTNUM);
  908. end;
  909. {TODO:AS_ID}
  910. else
  911. begin
  912. { error: expected integer }
  913. result.Free;
  914. result:=nil;
  915. Consume(AS_INTNUM);
  916. end;
  917. end;
  918. a_global_get,
  919. a_global_set:
  920. case actasmtoken of
  921. AS_INTNUM:
  922. begin
  923. result.ops:=1;
  924. result.operands[1].opr.typ:=OPR_CONSTANT;
  925. result.operands[1].opr.val:=actinttoken;
  926. Consume(AS_INTNUM);
  927. end;
  928. AS_ID:
  929. begin
  930. case actasmpattern of
  931. '$'+STACK_POINTER_SYM:
  932. begin
  933. result.ops:=1;
  934. result.operands[1].opr.typ:=OPR_SYMBOL;
  935. result.operands[1].opr.symbol:=thlcgwasm(hlcg).RefStackPointerSym;
  936. Consume(AS_ID);
  937. end;
  938. '$'+TLS_SIZE_SYM,
  939. '$'+TLS_ALIGN_SYM,
  940. '$'+TLS_BASE_SYM:
  941. begin
  942. globsym:=TWasmGlobalAsmSymbol(
  943. current_asmdata.RefAsmSymbolByClass(
  944. TWasmGlobalAsmSymbol,
  945. Copy(actasmpattern,2,Length(actasmpattern)-1),
  946. AT_WASM_GLOBAL));
  947. globsym.WasmGlobalType:=wbt_i32;
  948. result.ops:=1;
  949. result.operands[1].opr.typ:=OPR_SYMBOL;
  950. result.operands[1].opr.symbol:=globsym;
  951. Consume(AS_ID);
  952. end;
  953. else
  954. internalerror(2024072002);
  955. end;
  956. end;
  957. else
  958. begin
  959. { error: expected integer }
  960. result.Free;
  961. result:=nil;
  962. Consume(AS_INTNUM);
  963. end;
  964. end;
  965. a_call:
  966. case actasmtoken of
  967. AS_ID:
  968. begin
  969. AsmSearchSym(upper(Copy(actasmpattern,2,Length(actasmpattern)-1)),srsym,srsymtable);
  970. if assigned(srsym) then
  971. begin
  972. case srsym.typ of
  973. procsym:
  974. begin
  975. if Tprocsym(srsym).ProcdefList.Count>1 then
  976. Message(asmr_w_calling_overload_func);
  977. result.ops:=2;
  978. result.operands[1].opr.typ:=OPR_SYMBOL;
  979. result.operands[1].opr.symbol:=current_asmdata.RefAsmSymbol(tprocdef(tprocsym(srsym).ProcdefList[0]).mangledname,AT_FUNCTION);
  980. result.operands[2].opr.typ:=OPR_FUNCTYPE;
  981. result.operands[2].opr.functype:=tcpuprocdef(tprocsym(srsym).ProcdefList[0]).create_functype;
  982. Consume(AS_ID);
  983. end;
  984. else
  985. Message(asmr_e_wrong_sym_type);
  986. end;
  987. end
  988. else
  989. Message1(sym_e_unknown_id,actasmpattern);
  990. end;
  991. else
  992. begin
  993. { error: expected identifier }
  994. result.Free;
  995. result:=nil;
  996. Consume(AS_ID);
  997. end;
  998. end;
  999. else
  1000. internalerror(2024071401);
  1001. end;
  1002. end;
  1003. else
  1004. internalerror(2024071604);
  1005. end;
  1006. end;
  1007. procedure twasmreader.HandleBlockInstruction;
  1008. var
  1009. instr: TWasmInstruction;
  1010. begin
  1011. if actasmtoken<>AS_OPCODE then
  1012. internalerror(2024071601);
  1013. case actopcode of
  1014. a_if,
  1015. a_block,
  1016. a_loop:
  1017. begin
  1018. instr:=TWasmInstruction.create(TWasmOperand);
  1019. instr.opcode:=actopcode;
  1020. Consume(AS_OPCODE);
  1021. {TODO: implement the rest}
  1022. internalerror(2024071699);
  1023. end;
  1024. else
  1025. internalerror(2024071602);
  1026. end;
  1027. end;
  1028. function twasmreader.Assemble: tlinkedlist;
  1029. begin
  1030. Message1(asmr_d_start_reading,'WebAssembly');
  1031. firsttoken:=TRUE;
  1032. { sets up all opcode and register tables in uppercase }
  1033. if not _asmsorted then
  1034. begin
  1035. SetupTables;
  1036. _asmsorted:=TRUE;
  1037. end;
  1038. curlist:=TAsmList.Create;
  1039. { we might need to know which parameters are passed in registers }
  1040. if not parse_generic then
  1041. current_procinfo.generate_parameter_info;
  1042. { start tokenizer }
  1043. gettoken;
  1044. { main loop }
  1045. repeat
  1046. case actasmtoken of
  1047. AS_END:
  1048. break; { end assembly block }
  1049. AS_OPCODE,
  1050. AS_LPAREN:
  1051. HandleInstruction;
  1052. else
  1053. begin
  1054. Consume(actasmtoken);
  1055. //Message(asmr_e_syntax_error);
  1056. //RecoverConsume(false);
  1057. end;
  1058. end;
  1059. until false;
  1060. { Return the list in an asmnode }
  1061. assemble:=curlist;
  1062. Message1(asmr_d_finish_reading,'WebAssembly');
  1063. end;
  1064. {*****************************************************************************
  1065. Initialize
  1066. *****************************************************************************}
  1067. const
  1068. asmmode_wasm_standard_info : tasmmodeinfo =
  1069. (
  1070. id : asmmode_standard;
  1071. idtxt : 'STANDARD';
  1072. casmreader : twasmreader;
  1073. );
  1074. initialization
  1075. RegisterAsmMode(asmmode_wasm_standard_info);
  1076. end.