rawasmtext.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  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,
  69. { parser }
  70. scanner,pbase,
  71. procinfo,
  72. rabase,rautils,
  73. cgbase,cgutils,cgobj,
  74. { wasm }
  75. itcpuwasm
  76. ;
  77. {*****************************************************************************
  78. twasmreader
  79. *****************************************************************************}
  80. procedure twasmreader.SetupTables;
  81. var
  82. i: TAsmOp;
  83. begin
  84. iasmops:=TFPHashList.create;
  85. for i:=firstop to lastop do
  86. if wasm_op2str[i]<>'end' then
  87. iasmops.Add(wasm_op2str[i],Pointer(PtrInt(i)));
  88. end;
  89. procedure twasmreader.GetToken;
  90. var
  91. has_sign, is_hex, is_float: Boolean;
  92. function GetIntToken: aint;
  93. var
  94. s: string;
  95. u64: UInt64;
  96. begin
  97. s:=actasmpattern;
  98. if has_sign and (s[1]='-') then
  99. begin
  100. delete(s,1,1);
  101. if is_hex then
  102. begin
  103. delete(s,1,2);
  104. Val('$'+s,u64);
  105. end
  106. else
  107. Val(s,u64);
  108. {$push} {$R-}{$Q-}
  109. result:=aint(-u64);
  110. {$pop}
  111. end
  112. else
  113. begin
  114. if has_sign then
  115. delete(s,1,1);
  116. if is_hex then
  117. begin
  118. delete(s,1,2);
  119. Val('$'+s,u64);
  120. end
  121. else
  122. Val(s,u64);
  123. result:=aint(u64);
  124. end;
  125. end;
  126. function GetFloatToken: double;
  127. var
  128. s: string;
  129. begin
  130. s:=actasmpattern;
  131. if is_hex then
  132. begin
  133. { TODO: parse hex floats }
  134. internalerror(2024071501);
  135. end
  136. else
  137. Val(s,result);
  138. end;
  139. var
  140. len: Integer;
  141. tmpS: string;
  142. tmpI, tmpCode: Integer;
  143. begin
  144. c:=scanner.c;
  145. { save old token and reset new token }
  146. prevasmtoken:=actasmtoken;
  147. actasmtoken:=AS_NONE;
  148. { reset }
  149. actasmpattern:='';
  150. { while space, tab, new line or comment, continue scan... }
  151. while c in [' ',#9,#13,#10] do
  152. begin
  153. c:=current_scanner.asmgetchar;
  154. case c of
  155. ';':
  156. begin
  157. c:=current_scanner.asmgetchar;
  158. case c of
  159. { ;; comment until end of line }
  160. ';':
  161. begin
  162. { skip until end of line }
  163. repeat
  164. c:=current_scanner.asmgetchar;
  165. until c in [#13,#10];
  166. end;
  167. else
  168. current_scanner.illegal_char(c);
  169. end;
  170. end;
  171. '(':
  172. begin
  173. current_scanner.gettokenpos;
  174. c:=current_scanner.asmgetchar;
  175. case c of
  176. { (; block comment ;) }
  177. ';':
  178. begin
  179. { skip until ;) }
  180. repeat
  181. c:=current_scanner.asmgetchar;
  182. if c=';' then
  183. begin
  184. c:=current_scanner.asmgetchar;
  185. if c=')' then
  186. begin
  187. c:=current_scanner.asmgetchar;
  188. break;
  189. end;
  190. end;
  191. until false;
  192. end;
  193. else
  194. begin
  195. actasmtoken:=AS_LPAREN;
  196. exit;
  197. end;
  198. end;
  199. end;
  200. end;
  201. end;
  202. current_scanner.gettokenpos;
  203. case c of
  204. ')':
  205. begin
  206. c:=current_scanner.asmgetchar;
  207. actasmtoken:=AS_RPAREN;
  208. end;
  209. '$','a'..'z','A'..'Z':
  210. begin
  211. len:=0;
  212. while c in ['A'..'Z','a'..'z','0'..'9',
  213. '!','#','$','%','&','''','*','+','-','.','/',
  214. ':','<','=','>','?','@','\','^','_','`','|','~'] do
  215. begin
  216. inc(len);
  217. actasmpattern[len]:=c;
  218. c:=current_scanner.asmgetchar;
  219. end;
  220. actasmpattern[0]:=chr(len);
  221. actasmpattern_origcase:=actasmpattern;
  222. if actasmpattern[1]='$' then
  223. actasmtoken:=AS_ID
  224. else if is_asmopcode(actasmpattern) or
  225. is_valtype(actasmpattern) then
  226. exit
  227. else if upper(actasmpattern) = 'END' then
  228. begin
  229. uppervar(actasmpattern);
  230. actasmtoken:=AS_END;
  231. exit;
  232. end
  233. else
  234. begin
  235. message1(asmr_e_unknown_opcode,actasmpattern);
  236. actasmtoken:=AS_NONE;
  237. end;
  238. end;
  239. '0'..'9','+','-':
  240. begin
  241. len:=0;
  242. has_sign:=false;
  243. is_hex:=false;
  244. is_float:=false;
  245. if c in ['+','-'] then
  246. begin
  247. has_sign:=true;
  248. inc(len);
  249. actasmpattern[len]:=c;
  250. c:=current_scanner.asmgetchar;
  251. end;
  252. if c='0' then
  253. begin
  254. inc(len);
  255. actasmpattern[len]:=c;
  256. c:=current_scanner.asmgetchar;
  257. if c='x' then
  258. begin
  259. is_hex:=true;
  260. inc(len);
  261. actasmpattern[len]:=c;
  262. c:=current_scanner.asmgetchar;
  263. end;
  264. end;
  265. if is_hex then
  266. begin
  267. while c in ['0'..'9','a'..'f','A'..'F'] do
  268. begin
  269. inc(len);
  270. actasmpattern[len]:=c;
  271. c:=current_scanner.asmgetchar;
  272. end;
  273. end
  274. else
  275. begin
  276. while c in ['0'..'9'] do
  277. begin
  278. inc(len);
  279. actasmpattern[len]:=c;
  280. c:=current_scanner.asmgetchar;
  281. end;
  282. end;
  283. if c='.' then
  284. begin
  285. is_float:=true;
  286. inc(len);
  287. actasmpattern[len]:=c;
  288. c:=current_scanner.asmgetchar;
  289. { parse the fractional part }
  290. if is_hex then
  291. begin
  292. while c in ['0'..'9','a'..'f','A'..'F'] do
  293. begin
  294. inc(len);
  295. actasmpattern[len]:=c;
  296. c:=current_scanner.asmgetchar;
  297. end;
  298. end
  299. else
  300. begin
  301. while c in ['0'..'9'] do
  302. begin
  303. inc(len);
  304. actasmpattern[len]:=c;
  305. c:=current_scanner.asmgetchar;
  306. end;
  307. end;
  308. end;
  309. if (is_hex and (c in ['p','P'])) or
  310. ((not is_hex) and (c in ['e','E'])) then
  311. begin
  312. inc(len);
  313. actasmpattern[len]:=c;
  314. c:=current_scanner.asmgetchar;
  315. if c in ['+','-'] then
  316. begin
  317. inc(len);
  318. actasmpattern[len]:=c;
  319. c:=current_scanner.asmgetchar;
  320. end;
  321. while c in ['0'..'9'] do
  322. begin
  323. inc(len);
  324. actasmpattern[len]:=c;
  325. c:=current_scanner.asmgetchar;
  326. end;
  327. end;
  328. actasmpattern[0]:=chr(len);
  329. if is_float then
  330. begin
  331. actasmtoken:=AS_REALNUM;
  332. actfloattoken:=GetFloatToken;
  333. end
  334. else
  335. begin
  336. actasmtoken:=AS_INTNUM;
  337. actinttoken:=GetIntToken;
  338. end;
  339. end;
  340. '"':
  341. begin
  342. actasmpattern:='';
  343. repeat
  344. c:=current_scanner.asmgetchar;
  345. case c of
  346. '\' :
  347. begin
  348. c:=current_scanner.asmgetchar;
  349. case c of
  350. 't':
  351. begin
  352. actasmpattern:=actasmpattern+#9;
  353. c:=current_scanner.asmgetchar;
  354. end;
  355. 'n':
  356. begin
  357. actasmpattern:=actasmpattern+#10;
  358. c:=current_scanner.asmgetchar;
  359. end;
  360. 'r':
  361. begin
  362. actasmpattern:=actasmpattern+#13;
  363. c:=current_scanner.asmgetchar;
  364. end;
  365. '"':
  366. begin
  367. actasmpattern:=actasmpattern+'"';
  368. c:=current_scanner.asmgetchar;
  369. end;
  370. '''':
  371. begin
  372. actasmpattern:=actasmpattern+'''';
  373. c:=current_scanner.asmgetchar;
  374. end;
  375. '\':
  376. begin
  377. actasmpattern:=actasmpattern+'\';
  378. c:=current_scanner.asmgetchar;
  379. end;
  380. 'u':
  381. begin
  382. tmpS:='';
  383. c:=current_scanner.asmgetchar;
  384. while c in ['0'..'9','a'..'f','A'..'F'] do
  385. begin
  386. tmpS:=tmpS+c;
  387. c:=current_scanner.asmgetchar;
  388. end;
  389. if tmpS<>'' then
  390. begin
  391. Val('$'+tmpS,tmpI,tmpCode);
  392. if (tmpI<$D800) or ((tmpI>=$E000) and (tmpI<$110000)) then
  393. begin
  394. if tmpI<=$7F then
  395. actasmpattern:=actasmpattern+Chr(tmpI)
  396. else if tmpI<=$7FF then
  397. actasmpattern:=actasmpattern+
  398. Chr(%11000000 or (tmpI shr 6))+
  399. Chr(%10000000 or (tmpI and $3F))
  400. else if tmpI<=$FFFF then
  401. actasmpattern:=actasmpattern+
  402. Chr(%11100000 or (tmpI shr 12))+
  403. Chr(%10000000 or ((tmpI shr 6) and $3F))+
  404. Chr(%10000000 or (tmpI and $3F))
  405. else
  406. actasmpattern:=actasmpattern+
  407. Chr(%11110000 or (tmpI shr 18))+
  408. Chr(%10000000 or ((tmpI shr 12) and $3F))+
  409. Chr(%10000000 or ((tmpI shr 6) and $3F))+
  410. Chr(%10000000 or (tmpI and $3F))
  411. end
  412. else
  413. Message1(asmr_e_escape_seq_ignored,'u'+tmpS);
  414. end
  415. else
  416. Message1(asmr_e_escape_seq_ignored,'u');
  417. end;
  418. '0'..'9','a'..'f','A'..'F':
  419. begin
  420. tmpS:=c;
  421. c:=current_scanner.asmgetchar;
  422. if c in ['0'..'9','a'..'f','A'..'F'] then
  423. begin
  424. tmpS:=tmpS+c;
  425. c:=current_scanner.asmgetchar;
  426. Val('$'+tmpS,tmpI,tmpCode);
  427. actasmpattern:=actasmpattern+Chr(tmpI);
  428. end
  429. else
  430. begin
  431. Message1(asmr_e_escape_seq_ignored,tmpS+c);
  432. c:=current_scanner.asmgetchar;
  433. end;
  434. end;
  435. else
  436. begin
  437. Message1(asmr_e_escape_seq_ignored,c);
  438. c:=current_scanner.asmgetchar;
  439. end;
  440. end;
  441. end;
  442. '"' :
  443. begin
  444. c:=current_scanner.asmgetchar;
  445. break;
  446. end;
  447. #10,#13:
  448. Message(scan_f_string_exceeds_line);
  449. #0..#9,#11,#12,#14..#31,#127:
  450. current_scanner.illegal_char(c);
  451. else
  452. actasmpattern:=actasmpattern+c;
  453. end;
  454. until false;
  455. actasmtoken:=AS_STRING;
  456. exit;
  457. end;
  458. else
  459. current_scanner.illegal_char(c);
  460. end;
  461. end;
  462. function twasmreader.consume(t: tasmtoken): boolean;
  463. begin
  464. Consume:=true;
  465. if t<>actasmtoken then
  466. begin
  467. Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]);
  468. Consume:=false;
  469. end;
  470. repeat
  471. gettoken;
  472. until actasmtoken<>AS_NONE;
  473. end;
  474. function twasmreader.is_asmopcode(const s: string): boolean;
  475. begin
  476. actopcode:=tasmop(PtrUInt(iasmops.Find(s)));
  477. if actopcode<>A_NONE then
  478. begin
  479. actasmtoken:=AS_OPCODE;
  480. is_asmopcode:=true;
  481. end
  482. else
  483. is_asmopcode:=false;
  484. end;
  485. function twasmreader.is_valtype(const s: string): boolean;
  486. begin
  487. actwasmbasictype:=wbt_Unknown;
  488. case s of
  489. 'i32':
  490. actwasmbasictype:=wbt_i32;
  491. 'i64':
  492. actwasmbasictype:=wbt_i64;
  493. 'f32':
  494. actwasmbasictype:=wbt_f32;
  495. 'f64':
  496. actwasmbasictype:=wbt_f64;
  497. 'funcref':
  498. actwasmbasictype:=wbt_funcref;
  499. 'externref':
  500. actwasmbasictype:=wbt_externref;
  501. 'v128':
  502. actwasmbasictype:=wbt_v128;
  503. end;
  504. if actwasmbasictype<>wbt_Unknown then
  505. begin
  506. actasmtoken:=AS_VALTYPE;
  507. is_valtype:=true;
  508. end
  509. else
  510. is_valtype:=false;
  511. end;
  512. procedure twasmreader.HandleInstruction;
  513. var
  514. instr: TWasmInstruction;
  515. begin
  516. case actasmtoken of
  517. AS_LPAREN:
  518. begin
  519. Consume(AS_LPAREN);
  520. HandleFoldedInstruction;
  521. end;
  522. AS_OPCODE:
  523. begin
  524. case actopcode of
  525. a_block,
  526. a_loop,
  527. a_if:
  528. HandleBlockInstruction;
  529. else
  530. begin
  531. instr:=HandlePlainInstruction;
  532. instr.ConcatInstruction(curlist);
  533. end;
  534. end;
  535. end;
  536. else
  537. internalerror(2024071603);
  538. end;
  539. end;
  540. procedure twasmreader.HandleFoldedInstruction;
  541. var
  542. HasLabel, HasType, HasParam, HasResult, HasInstructions,
  543. HasThen, HasElse: Boolean;
  544. instr: TWasmInstruction;
  545. tmpS: string;
  546. begin
  547. instr:=nil;
  548. //Consume(AS_LPAREN);
  549. case actasmtoken of
  550. AS_OPCODE:
  551. begin
  552. case actopcode of
  553. a_block,
  554. a_loop,
  555. a_if:
  556. begin
  557. Consume(AS_OPCODE);
  558. HasType:=False;
  559. HasParam:=False;
  560. HasResult:=False;
  561. HasInstructions:=False;
  562. HasThen:=False;
  563. HasElse:=False;
  564. instr:=TWasmInstruction.create(TWasmOperand);
  565. instr.opcode:=actopcode;
  566. HasLabel:=False;
  567. if actasmtoken=AS_ID then
  568. begin
  569. Consume(AS_ID);
  570. HasLabel:=True;
  571. end;
  572. repeat
  573. case actasmtoken of
  574. AS_LPAREN:
  575. begin
  576. Consume(AS_LPAREN);
  577. case actasmtoken of
  578. AS_TYPE:
  579. begin
  580. if HasElse or HasThen or HasInstructions or HasResult or HasParam or HasType then
  581. begin
  582. {TODO: error}
  583. end;
  584. Consume(AS_TYPE);
  585. //TODO: consume u32 or id
  586. Consume(actasmtoken);
  587. Consume(AS_RPAREN);
  588. end;
  589. AS_PARAM:
  590. begin
  591. if HasElse or HasThen or HasInstructions or HasResult then
  592. begin
  593. {TODO: error}
  594. end;
  595. Consume(AS_PARAM);
  596. if actasmtoken=AS_ID then
  597. begin
  598. tmpS:=actasmpattern;
  599. Consume(AS_ID);
  600. if actasmtoken=AS_VALTYPE then
  601. instr.AddParam(actasmpattern,actwasmbasictype);
  602. Consume(AS_VALTYPE);
  603. end
  604. else
  605. begin
  606. while actasmtoken<>AS_RPAREN do
  607. begin
  608. if actasmtoken=AS_VALTYPE then
  609. instr.AddParam('',actwasmbasictype);
  610. Consume(AS_VALTYPE);
  611. end;
  612. end;
  613. Consume(AS_RPAREN);
  614. end;
  615. AS_RESULT:
  616. begin
  617. if HasElse or HasThen or HasInstructions then
  618. begin
  619. {TODO: error}
  620. end;
  621. Consume(AS_RESULT);
  622. while actasmtoken<>AS_RPAREN do
  623. begin
  624. if actasmtoken=AS_VALTYPE then
  625. instr.AddResult(actwasmbasictype);
  626. Consume(AS_VALTYPE);
  627. end;
  628. Consume(AS_RPAREN);
  629. end;
  630. AS_THEN:
  631. begin
  632. if instr.opcode<>a_if then
  633. {error!};
  634. Consume(AS_THEN);
  635. HasThen:=True;
  636. while actasmtoken<>AS_RPAREN do
  637. HandleInstruction;
  638. Consume(AS_RPAREN);
  639. end;
  640. AS_ELSE:
  641. begin
  642. if instr.opcode<>a_if then
  643. {error!};
  644. Consume(AS_ELSE);
  645. HasElse:=True;
  646. while actasmtoken<>AS_RPAREN do
  647. HandleInstruction;
  648. Consume(AS_RPAREN);
  649. end;
  650. else
  651. begin
  652. HasInstructions:=True;
  653. HandleFoldedInstruction;
  654. end;
  655. end;
  656. end;
  657. else
  658. {todo: error};
  659. end;
  660. until false;
  661. end;
  662. else
  663. begin
  664. instr:=HandlePlainInstruction;
  665. while actasmtoken<>AS_RPAREN do
  666. begin
  667. Consume(AS_LPAREN);
  668. HandleFoldedInstruction;
  669. end;
  670. instr.ConcatInstruction(curlist);
  671. instr.Free;
  672. instr:=nil;
  673. Consume(AS_RPAREN);
  674. end;
  675. end;
  676. end;
  677. else
  678. {error}
  679. end;
  680. end;
  681. function twasmreader.HandlePlainInstruction: TWasmInstruction;
  682. begin
  683. result:=nil;
  684. case actasmtoken of
  685. AS_OPCODE:
  686. begin
  687. result:=TWasmInstruction.create(TWasmOperand);
  688. result.opcode:=actopcode;
  689. Consume(AS_OPCODE);
  690. case result.opcode of
  691. { instructions, which require 0 operands }
  692. a_nop,
  693. a_unreachable,
  694. a_return,
  695. a_ref_is_null,
  696. a_drop,
  697. a_memory_size,
  698. a_memory_grow,
  699. a_memory_fill,
  700. a_memory_copy,
  701. 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,
  702. 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,
  703. 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,
  704. 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,
  705. 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,
  706. 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,
  707. a_f32_eq,a_f32_ne,a_f32_lt,a_f32_gt,a_f32_le,a_f32_ge,
  708. a_f64_eq,a_f64_ne,a_f64_lt,a_f64_gt,a_f64_le,a_f64_ge,
  709. a_i32_wrap_i64,
  710. a_i32_trunc_f32_s,
  711. a_i32_trunc_f32_u,
  712. a_i32_trunc_f64_s,
  713. a_i32_trunc_f64_u,
  714. a_i32_trunc_sat_f32_s,
  715. a_i32_trunc_sat_f32_u,
  716. a_i32_trunc_sat_f64_s,
  717. a_i32_trunc_sat_f64_u,
  718. a_i64_extend_i32_s,
  719. a_i64_extend_i32_u,
  720. a_i64_trunc_f32_s,
  721. a_i64_trunc_f32_u,
  722. a_i64_trunc_f64_s,
  723. a_i64_trunc_f64_u,
  724. a_i64_trunc_sat_f32_s,
  725. a_i64_trunc_sat_f32_u,
  726. a_i64_trunc_sat_f64_u,
  727. a_i64_trunc_sat_f64_s,
  728. a_f32_convert_i32_s,
  729. a_f32_convert_i32_u,
  730. a_f32_convert_i64_s,
  731. a_f32_convert_i64_u,
  732. a_f32_demote_f64,
  733. a_f64_convert_i32_s,
  734. a_f64_convert_i32_u,
  735. a_f64_convert_i64_s,
  736. a_f64_convert_i64_u,
  737. a_f64_promote_f32,
  738. a_i32_reinterpret_f32,
  739. a_i64_reinterpret_f64,
  740. a_f32_reinterpret_i32,
  741. a_f64_reinterpret_i64,
  742. a_i32_extend8_s,
  743. a_i32_extend16_s,
  744. a_i64_extend8_s,
  745. a_i64_extend16_s,
  746. a_i64_extend32_s:
  747. ;
  748. { instructions with an integer const operand }
  749. a_i32_const,
  750. a_i64_const:
  751. begin
  752. if actasmtoken=AS_INTNUM then
  753. begin
  754. result.ops:=1;
  755. result.operands[1].opr.typ:=OPR_CONSTANT;
  756. result.operands[1].opr.val:=actinttoken;
  757. Consume(AS_INTNUM);
  758. end
  759. else
  760. begin
  761. { error: expected integer }
  762. result.Free;
  763. result:=nil;
  764. Consume(AS_INTNUM);
  765. end;
  766. end;
  767. { instructions with a float const operand }
  768. a_f32_const,
  769. a_f64_const:
  770. begin
  771. case actasmtoken of
  772. AS_INTNUM:
  773. begin
  774. result.ops:=1;
  775. result.operands[1].opr.typ:=OPR_FLOATCONSTANT;
  776. result.operands[1].opr.floatval:=actinttoken;
  777. Consume(AS_INTNUM);
  778. end;
  779. AS_REALNUM:
  780. begin
  781. result.ops:=1;
  782. result.operands[1].opr.typ:=OPR_FLOATCONSTANT;
  783. result.operands[1].opr.floatval:=actfloattoken;
  784. Consume(AS_REALNUM);
  785. end;
  786. else
  787. begin
  788. { error: expected real }
  789. result.Free;
  790. result:=nil;
  791. Consume(AS_REALNUM);
  792. end;
  793. end;
  794. end;
  795. { instructions with an optional memarg operand }
  796. a_i32_load,
  797. a_i64_load,
  798. a_f32_load,
  799. a_f64_load,
  800. a_i32_load8_s,
  801. a_i32_load8_u,
  802. a_i32_load16_s,
  803. a_i32_load16_u,
  804. a_i64_load8_s,
  805. a_i64_load8_u,
  806. a_i64_load16_s,
  807. a_i64_load16_u,
  808. a_i64_load32_s,
  809. a_i64_load32_u,
  810. a_i32_store,
  811. a_i64_store,
  812. a_f32_store,
  813. a_f64_store,
  814. a_i32_store8,
  815. a_i32_store16,
  816. a_i64_store8,
  817. a_i64_store16,
  818. a_i64_store32:
  819. begin
  820. { TODO: parse the optional memarg operand }
  821. result.ops:=1;
  822. result.operands[1].opr.typ:=OPR_CONSTANT;
  823. result.operands[1].opr.val:=0;
  824. end;
  825. { instructions that take a local variable parameter (or index) }
  826. a_local_get,
  827. a_local_set,
  828. a_local_tee:
  829. case actasmtoken of
  830. AS_INTNUM:
  831. begin
  832. result.ops:=1;
  833. result.operands[1].opr.typ:=OPR_CONSTANT;
  834. result.operands[1].opr.val:=actinttoken;
  835. Consume(AS_INTNUM);
  836. end;
  837. {TODO:AS_ID}
  838. else
  839. begin
  840. { error: expected integer }
  841. result.Free;
  842. result:=nil;
  843. Consume(AS_INTNUM);
  844. end;
  845. end;
  846. a_global_get,
  847. a_global_set:
  848. case actasmtoken of
  849. AS_INTNUM:
  850. begin
  851. result.ops:=1;
  852. result.operands[1].opr.typ:=OPR_CONSTANT;
  853. result.operands[1].opr.val:=actinttoken;
  854. Consume(AS_INTNUM);
  855. end;
  856. {TODO:AS_ID}
  857. else
  858. begin
  859. { error: expected integer }
  860. result.Free;
  861. result:=nil;
  862. Consume(AS_INTNUM);
  863. end;
  864. end;
  865. else
  866. internalerror(2024071401);
  867. end;
  868. end;
  869. else
  870. internalerror(2024071604);
  871. end;
  872. end;
  873. procedure twasmreader.HandleBlockInstruction;
  874. var
  875. instr: TWasmInstruction;
  876. begin
  877. if actasmtoken<>AS_OPCODE then
  878. internalerror(2024071601);
  879. case actopcode of
  880. a_if,
  881. a_block,
  882. a_loop:
  883. begin
  884. instr:=TWasmInstruction.create(TWasmOperand);
  885. instr.opcode:=actopcode;
  886. Consume(AS_OPCODE);
  887. {TODO: implement the rest}
  888. internalerror(2024071699);
  889. end;
  890. else
  891. internalerror(2024071602);
  892. end;
  893. end;
  894. function twasmreader.Assemble: tlinkedlist;
  895. begin
  896. Message1(asmr_d_start_reading,'WebAssembly');
  897. firsttoken:=TRUE;
  898. { sets up all opcode and register tables in uppercase }
  899. if not _asmsorted then
  900. begin
  901. SetupTables;
  902. _asmsorted:=TRUE;
  903. end;
  904. curlist:=TAsmList.Create;
  905. { we might need to know which parameters are passed in registers }
  906. if not parse_generic then
  907. current_procinfo.generate_parameter_info;
  908. { start tokenizer }
  909. gettoken;
  910. { main loop }
  911. repeat
  912. Writeln(actasmtoken);
  913. case actasmtoken of
  914. AS_END:
  915. break; { end assembly block }
  916. AS_OPCODE,
  917. AS_LPAREN:
  918. HandleInstruction;
  919. else
  920. begin
  921. Consume(actasmtoken);
  922. //Message(asmr_e_syntax_error);
  923. //RecoverConsume(false);
  924. end;
  925. end;
  926. until false;
  927. { Return the list in an asmnode }
  928. assemble:=curlist;
  929. Message1(asmr_d_finish_reading,'WebAssembly');
  930. end;
  931. {*****************************************************************************
  932. Initialize
  933. *****************************************************************************}
  934. const
  935. asmmode_wasm_standard_info : tasmmodeinfo =
  936. (
  937. id : asmmode_standard;
  938. idtxt : 'STANDARD';
  939. casmreader : twasmreader;
  940. );
  941. initialization
  942. RegisterAsmMode(asmmode_wasm_standard_info);
  943. end.