racpugas.pas 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  1. {
  2. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  3. Copyright (c) 2014 by Jonas Maebe
  4. Does the parsing for the AArch64 GNU AS 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 racpugas;
  19. {$i fpcdefs.inc}
  20. Interface
  21. uses
  22. raatt,racpu,
  23. aasmtai,
  24. cgbase,cpubase;
  25. type
  26. { taarch64attreader }
  27. taarch64attreader = class(tattreader)
  28. actoppostfix : TOpPostfix;
  29. actinsmmsubreg : TSubRegister;
  30. actsehdirective : TAsmSehDirective;
  31. function is_asmopcode(const s: string):boolean;override;
  32. function is_register(const s:string):boolean;override;
  33. function is_targetdirective(const s: string): boolean;override;
  34. procedure handleopcode;override;
  35. procedure handletargetdirective; override;
  36. protected
  37. procedure BuildReference(oper: taarch64operand; is64bit: boolean);
  38. procedure BuildOperand(oper: taarch64operand; is64bit: boolean);
  39. function TryBuildShifterOp(instr: taarch64instruction; opnr: longint) : boolean;
  40. procedure BuildOpCode(instr: taarch64instruction);
  41. procedure ReadSym(oper: taarch64operand; is64bit: boolean);
  42. procedure ConvertCalljmp(instr: taarch64instruction);
  43. function ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  44. function ParseArrangementSpecifier(const hs: string): TSubRegister;
  45. function ParseRegIndex(const hs: string): byte;
  46. end;
  47. Implementation
  48. uses
  49. { helpers }
  50. cutils,
  51. { global }
  52. globtype,verbose,
  53. systems,aasmbase,aasmdata,aasmcpu,
  54. { symtable }
  55. symconst,symsym,symdef,
  56. procinfo,
  57. rabase,rautils,
  58. cgutils,paramgr;
  59. function taarch64attreader.is_register(const s:string):boolean;
  60. type
  61. treg2str = record
  62. name : string[3];
  63. reg : tregister;
  64. end;
  65. const
  66. extraregs : array[0..4] of treg2str = (
  67. (name: 'FP' ; reg: NR_FP),
  68. (name: 'LR' ; reg: NR_LR),
  69. (name: 'XR' ; reg: NR_XR),
  70. (name: 'IP0'; reg: NR_IP0),
  71. (name: 'IP1'; reg: NR_IP1));
  72. var
  73. i : longint;
  74. begin
  75. result:=inherited is_register(s);
  76. { reg found?
  77. possible aliases are always 2 chars
  78. }
  79. if result or not(length(s) in [2]) then
  80. exit;
  81. for i:=low(extraregs) to high(extraregs) do
  82. begin
  83. if s=extraregs[i].name then
  84. begin
  85. actasmregister:=extraregs[i].reg;
  86. result:=true;
  87. actasmtoken:=AS_REGISTER;
  88. exit;
  89. end;
  90. end;
  91. end;
  92. const
  93. { Aarch64 subset of SEH directives. .seh_proc, .seh_endproc and .seh_endepilogue
  94. excluded because they are generated automatically when needed. }
  95. recognized_directives: set of TAsmSehDirective=[
  96. ash_endprologue,ash_handler,ash_handlerdata,
  97. ash_stackalloc,ash_nop,ash_savefplr,ash_savefplr_x,
  98. ash_savereg,ash_savereg_x,ash_saveregp,ash_saveregp_x,
  99. ash_savefreg,ash_savefreg_x,ash_savefregp,ash_savefregp_x,
  100. ash_setfp,ash_addfp
  101. ];
  102. function taarch64attreader.is_targetdirective(const s: string): boolean;
  103. var
  104. i: TAsmSehDirective;
  105. begin
  106. result:=false;
  107. if target_info.system<>system_aarch64_win64 then
  108. exit;
  109. for i:=low(TAsmSehDirective) to high(TAsmSehDirective) do
  110. begin
  111. if not (i in recognized_directives) then
  112. continue;
  113. if s=sehdirectivestr[i] then
  114. begin
  115. actsehdirective:=i;
  116. result:=true;
  117. break;
  118. end;
  119. end;
  120. { allow SEH directives only in pure assember routines }
  121. if result and not (po_assembler in current_procinfo.procdef.procoptions) then
  122. begin
  123. Message(asmr_e_seh_in_pure_asm_only);
  124. result:=false;
  125. end;
  126. end;
  127. procedure taarch64attreader.ReadSym(oper: taarch64operand; is64bit: boolean);
  128. var
  129. tempstr, mangledname : string;
  130. typesize,l,k: aint;
  131. begin
  132. tempstr:=actasmpattern;
  133. Consume(AS_ID);
  134. { typecasting? }
  135. if (actasmtoken=AS_LPAREN) and
  136. SearchType(tempstr,typesize) then
  137. begin
  138. oper.hastype:=true;
  139. Consume(AS_LPAREN);
  140. BuildOperand(oper,is64bit);
  141. Consume(AS_RPAREN);
  142. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  143. oper.SetSize(typesize,true);
  144. end
  145. else
  146. if not oper.SetupVar(tempstr,false) then
  147. Message1(sym_e_unknown_id,tempstr);
  148. { record.field ? }
  149. if actasmtoken=AS_DOT then
  150. begin
  151. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  152. if (mangledname<>'') then
  153. Message(asmr_e_invalid_reference_syntax);
  154. inc(oper.opr.ref.offset,l);
  155. end;
  156. end;
  157. Procedure taarch64attreader.BuildReference(oper: taarch64operand; is64bit: boolean);
  158. procedure do_error;
  159. begin
  160. Message(asmr_e_invalid_reference_syntax);
  161. RecoverConsume(false);
  162. end;
  163. procedure test_end(require_rbracket : boolean);
  164. begin
  165. if require_rbracket then begin
  166. if not(actasmtoken=AS_RBRACKET) then
  167. begin
  168. do_error;
  169. exit;
  170. end
  171. else
  172. Consume(AS_RBRACKET);
  173. if (actasmtoken=AS_NOT) then
  174. begin
  175. oper.opr.ref.addressmode:=AM_PREINDEXED;
  176. Consume(AS_NOT);
  177. end;
  178. end;
  179. if not(actasmtoken in [AS_SEPARATOR,AS_end]) then
  180. do_error
  181. else
  182. begin
  183. {$IFDEF debugasmreader}
  184. writeln('TEST_end_FINAL_OK. Created the following ref:');
  185. writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm);
  186. writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode));
  187. writeln('oper.opr.ref.index=',ord(oper.opr.ref.index));
  188. writeln('oper.opr.ref.base=',ord(oper.opr.ref.base));
  189. writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex));
  190. writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode));
  191. writeln;
  192. {$endIF debugasmreader}
  193. end;
  194. end;
  195. function is_shifter_ref_operation(var a : tshiftmode) : boolean;
  196. begin
  197. a:=SM_NONE;
  198. if (actasmpattern='LSL') then
  199. a:=SM_LSL
  200. else if (actasmpattern='UXTW') then
  201. a:=SM_UXTW
  202. else if (actasmpattern='SXTW') then
  203. a:=SM_SXTW
  204. else if (actasmpattern='SXTX') then
  205. a:=SM_SXTX;
  206. is_shifter_ref_operation:=not(a=SM_NONE);
  207. end;
  208. procedure read_index_shift(require_rbracket : boolean);
  209. var
  210. shift: aint;
  211. begin
  212. case actasmtoken of
  213. AS_COMMA :
  214. begin
  215. Consume(AS_COMMA);
  216. if not(actasmtoken=AS_ID) then
  217. do_error;
  218. if is_shifter_ref_operation(oper.opr.ref.shiftmode) then
  219. begin
  220. Consume(actasmtoken);
  221. if actasmtoken=AS_HASH then
  222. begin
  223. Consume(AS_HASH);
  224. shift:=BuildConstExpression(false,true);
  225. if not(shift in [0,2+ord(is64bit)]) then
  226. do_error;
  227. oper.opr.ref.shiftimm:=shift;
  228. test_end(require_rbracket);
  229. end;
  230. end
  231. else
  232. begin
  233. do_error;
  234. exit;
  235. end;
  236. end;
  237. AS_RBRACKET :
  238. if require_rbracket then
  239. test_end(require_rbracket)
  240. else
  241. begin
  242. do_error;
  243. exit;
  244. end;
  245. AS_SEPARATOR,AS_END :
  246. if not require_rbracket then
  247. test_end(false)
  248. else
  249. do_error;
  250. else
  251. begin
  252. do_error;
  253. exit;
  254. end;
  255. end;
  256. end;
  257. procedure read_index(require_rbracket : boolean);
  258. var
  259. recname : string;
  260. o_int,s_int : aint;
  261. begin
  262. case actasmtoken of
  263. AS_REGISTER :
  264. begin
  265. if getsupreg(actasmregister)=RS_XZR then
  266. Message1(asmr_e_invalid_ref_register,actasmpattern);
  267. oper.opr.ref.index:=actasmregister;
  268. Consume(AS_REGISTER);
  269. read_index_shift(require_rbracket);
  270. exit;
  271. end;
  272. AS_HASH : // constant
  273. begin
  274. Consume(AS_HASH);
  275. (*
  276. if actasmtoken=AS_COLON then
  277. begin
  278. consume(AS_COLON);
  279. { GNU-style lower 12 bits of address of non-GOT-based
  280. access }
  281. if (actasmpattern='LO12') then
  282. begin
  283. consume(actasmtoken);
  284. consume(AS_COLON);
  285. if not oper.SetupVar(actasmpattern,false) then
  286. begin
  287. do_error;
  288. exit
  289. end;
  290. consume(AS_ID);
  291. oper.opr.ref.refaddr:=addr_??? (not gotpageoffset);
  292. end
  293. else
  294. begin
  295. do_error;
  296. exit
  297. end;
  298. end
  299. else
  300. *)
  301. begin
  302. o_int:=BuildConstExpression(false,true);
  303. inc(oper.opr.ref.offset,o_int);
  304. end;
  305. test_end(require_rbracket);
  306. exit;
  307. end;
  308. AS_ID :
  309. begin
  310. recname:=actasmpattern;
  311. Consume(AS_ID);
  312. { Apple-style got page offset }
  313. if actasmtoken=AS_AT then
  314. begin
  315. if not oper.SetupVar(recname,false) then
  316. begin
  317. do_error;
  318. exit
  319. end;
  320. consume(AS_AT);
  321. if actasmpattern='GOTPAGEOFF' then
  322. begin
  323. consume(actasmtoken);
  324. oper.opr.ref.refaddr:=addr_gotpageoffset;
  325. end
  326. else if actasmpattern='PAGEOFF' then
  327. begin
  328. consume(actasmtoken);
  329. oper.opr.ref.refaddr:=addr_pageoffset;
  330. end
  331. else
  332. begin
  333. do_error;
  334. exit
  335. end;
  336. end
  337. else
  338. begin
  339. BuildRecordOffsetSize(recname,o_int,s_int,recname,false);
  340. inc(oper.opr.ref.offset,o_int);
  341. end;
  342. test_end(require_rbracket);
  343. exit;
  344. end;
  345. AS_AT:
  346. begin
  347. do_error;
  348. exit;
  349. end;
  350. AS_RBRACKET :
  351. begin
  352. if require_rbracket then
  353. begin
  354. test_end(require_rbracket);
  355. exit;
  356. end
  357. else
  358. begin
  359. do_error; // unexpected rbracket
  360. exit;
  361. end;
  362. end;
  363. AS_SEPARATOR,AS_end :
  364. begin
  365. if not require_rbracket then
  366. begin
  367. test_end(false);
  368. exit;
  369. end
  370. else
  371. begin
  372. do_error;
  373. exit;
  374. end;
  375. end;
  376. else
  377. begin
  378. // unexpected token
  379. do_error;
  380. exit;
  381. end;
  382. end; // case
  383. end;
  384. procedure try_prepostindexed;
  385. begin
  386. Consume(AS_RBRACKET);
  387. case actasmtoken of
  388. AS_COMMA :
  389. begin // post-indexed
  390. Consume(AS_COMMA);
  391. oper.opr.ref.addressmode:=AM_POSTINDEXED;
  392. read_index(false);
  393. exit;
  394. end;
  395. AS_NOT :
  396. begin // pre-indexed
  397. Consume(AS_NOT);
  398. oper.opr.ref.addressmode:=AM_PREINDEXED;
  399. test_end(false);
  400. exit;
  401. end;
  402. else
  403. begin
  404. test_end(false);
  405. exit;
  406. end;
  407. end; // case
  408. end;
  409. begin
  410. Consume(AS_LBRACKET);
  411. oper.opr.ref.addressmode:=AM_OFFSET; // assume "neither PRE nor POST inc"
  412. if actasmtoken=AS_REGISTER then
  413. begin
  414. if getsupreg(actasmregister)=RS_XZR then
  415. Message1(asmr_e_invalid_ref_register,actasmpattern);
  416. oper.opr.ref.base:=actasmregister;
  417. Consume(AS_REGISTER);
  418. case actasmtoken of
  419. AS_RBRACKET :
  420. begin
  421. try_prepostindexed;
  422. exit;
  423. end;
  424. AS_COMMA :
  425. begin
  426. Consume(AS_COMMA);
  427. read_index(true);
  428. exit;
  429. end;
  430. else
  431. begin
  432. Message(asmr_e_invalid_reference_syntax);
  433. RecoverConsume(false);
  434. end;
  435. end;
  436. end
  437. else
  438. Begin
  439. case actasmtoken of
  440. AS_ID :
  441. begin
  442. { TODO: local variables and parameters }
  443. Message(asmr_e_invalid_reference_syntax);
  444. RecoverConsume(false);
  445. exit;
  446. end;
  447. else
  448. begin // elsecase
  449. Message(asmr_e_invalid_reference_syntax);
  450. RecoverConsume(false);
  451. exit;
  452. end;
  453. end;
  454. end;
  455. end;
  456. function taarch64attreader.TryBuildShifterOp(instr: taarch64instruction; opnr: longint): boolean;
  457. procedure handlepara(sm : tshiftmode);
  458. begin
  459. consume(AS_ID);
  460. fillchar(instr.operands[opnr].opr,sizeof(instr.operands[opnr].opr),0);
  461. instr.operands[opnr].opr.typ:=OPR_SHIFTEROP;
  462. instr.operands[opnr].opr.shifterop.shiftmode:=sm;
  463. if (sm=SM_LSL) or
  464. (actasmtoken=AS_HASH) then
  465. begin
  466. consume(AS_HASH);
  467. instr.operands[opnr].opr.shifterop.shiftimm:=BuildConstExpression(false,false);
  468. end;
  469. end;
  470. const
  471. shiftmode2str: array[SM_LSL..SM_SXTX] of string[4] =
  472. ('LSL','LSR','ASR','ROR',
  473. 'UXTB','UXTH','UXTW','UXTX',
  474. 'SXTB','SXTH','SXTW','SXTX');
  475. var
  476. sm: tshiftmode;
  477. i: longint;
  478. usessp,
  479. useszr: boolean;
  480. begin
  481. result:=false;
  482. if (actasmtoken=AS_ID) then
  483. begin
  484. for sm:=low(shiftmode2str) to high(shiftmode2str) do
  485. if actasmpattern=shiftmode2str[sm] then
  486. begin
  487. handlepara(sm);
  488. if instr.operands[1].opr.typ=OPR_REGISTER then
  489. begin
  490. { the possible shifter ops depend on whether this
  491. instruction uses sp and/or zr }
  492. usessp:=false;
  493. useszr:=false;
  494. for i:=low(instr.operands) to pred(opnr) do
  495. begin
  496. if (instr.operands[i].opr.typ=OPR_REGISTER) then
  497. case getsupreg(instr.operands[i].opr.reg) of
  498. RS_XZR:
  499. useszr:=true;
  500. RS_SP:
  501. usessp:=true;
  502. end;
  503. end;
  504. result:=valid_shifter_operand(instr.opcode,useszr,usessp,instr.Is64bit,sm,instr.operands[opnr].opr.shifterop.shiftimm);
  505. if result then
  506. instr.Ops:=opnr;
  507. end;
  508. break;
  509. end;
  510. end;
  511. end;
  512. function taarch64attreader.ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  513. begin
  514. case actopcode of
  515. A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM,
  516. A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP,
  517. A_B:
  518. begin
  519. { search for condition, conditions are always 2 chars }
  520. if (is_operand<>(actopcode=A_B)) and
  521. (length(hs)>1) then
  522. begin
  523. { workaround for DFA bug }
  524. result:=low(tasmcond);
  525. for result:=low(tasmcond) to high(tasmcond) do
  526. begin
  527. if hs=uppercond2str[result] then
  528. exit;
  529. end;
  530. end;
  531. end;
  532. else
  533. ;
  534. end;
  535. result:=C_None;
  536. end;
  537. function taarch64attreader.ParseArrangementSpecifier(const hs: string): TSubRegister;
  538. {$push}{$j-}
  539. const
  540. arrangements: array[R_SUBMM8B..R_SUBMM2D] of string[4] =
  541. ('.8B','.16B','.4H','.8H','.2S','.4S','.1D','.2D');
  542. {$pop}
  543. begin
  544. if length(hs)>2 then
  545. begin
  546. for result:=low(arrangements) to high(arrangements) do
  547. if hs=arrangements[result] then
  548. exit;
  549. result:=R_SUBNONE;
  550. end
  551. else
  552. case hs of
  553. '.B': result:=R_SUBMMB1;
  554. '.H': result:=R_SUBMMH1;
  555. '.S': result:=R_SUBMMS1;
  556. '.D': result:=R_SUBMMD1;
  557. else
  558. result:=R_SUBNONE;
  559. end
  560. end;
  561. function taarch64attreader.ParseRegIndex(const hs: string): byte;
  562. var
  563. b: cardinal;
  564. error: longint;
  565. begin
  566. b:=0;
  567. val(hs,b,error);
  568. if (error<>0) then
  569. Message(asmr_e_syn_constant)
  570. else if b > 31 then
  571. begin
  572. Message(asmr_e_constant_out_of_bounds);
  573. b:=0;
  574. end;
  575. result:=b;
  576. end;
  577. Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean);
  578. var
  579. expr: string;
  580. typesize, l: aint;
  581. procedure MaybeAddGotAddrMode;
  582. begin
  583. if actasmtoken=AS_AT then
  584. begin
  585. consume(AS_AT);
  586. if actasmpattern='GOTPAGE' then
  587. oper.opr.ref.refaddr:=addr_gotpage
  588. else if actasmpattern='GOTPAGEOFF' then
  589. oper.opr.ref.refaddr:=addr_gotpageoffset
  590. else if actasmpattern='PAGE' then
  591. oper.opr.ref.refaddr:=addr_page
  592. else if actasmpattern='PAGEOFF' then
  593. oper.opr.ref.refaddr:=addr_pageoffset
  594. else
  595. Message(asmr_e_expr_illegal);
  596. consume(actasmtoken);
  597. end
  598. else
  599. oper.opr.ref.refaddr:=addr_pic;
  600. end;
  601. procedure AddLabelOperand(hl:tasmlabel);
  602. begin
  603. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  604. is_calljmp(actopcode) then
  605. begin
  606. oper.opr.typ:=OPR_SYMBOL;
  607. oper.opr.symbol:=hl;
  608. end
  609. else if (actopcode=A_ADR) or
  610. (actopcode=A_ADRP) or
  611. (actopcode=A_LDR) then
  612. begin
  613. oper.InitRef;
  614. MaybeAddGotAddrMode;
  615. oper.opr.ref.symbol:=hl;
  616. if (actasmtoken in [AS_PLUS, AS_MINUS]) then
  617. begin
  618. l:=BuildConstExpression(true,false);
  619. oper.opr.ref.offset:=l;
  620. end;
  621. end;
  622. end;
  623. procedure MaybeRecordOffset;
  624. var
  625. mangledname: string;
  626. hasdot : boolean;
  627. l,
  628. toffset,
  629. tsize : aint;
  630. begin
  631. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  632. exit;
  633. l:=0;
  634. mangledname:='';
  635. hasdot:=(actasmtoken=AS_DOT);
  636. if hasdot then
  637. begin
  638. if expr<>'' then
  639. begin
  640. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  641. if (oper.opr.typ<>OPR_CONSTANT) and
  642. (mangledname<>'') then
  643. Message(asmr_e_wrong_sym_type);
  644. inc(l,toffset);
  645. oper.SetSize(tsize,true);
  646. end;
  647. end;
  648. if actasmtoken in [AS_PLUS,AS_MINUS] then
  649. inc(l,BuildConstExpression(true,false));
  650. case oper.opr.typ of
  651. OPR_LOCAL :
  652. begin
  653. { don't allow direct access to fields of parameters, because that
  654. will generate buggy code. Allow it only for explicit typecasting }
  655. if hasdot and
  656. (not oper.hastype) then
  657. checklocalsubscript(oper.opr.localsym);
  658. inc(oper.opr.localsymofs,l)
  659. end;
  660. OPR_CONSTANT :
  661. inc(oper.opr.val,l);
  662. OPR_REFERENCE :
  663. if (mangledname<>'') then
  664. begin
  665. if (oper.opr.val<>0) then
  666. Message(asmr_e_wrong_sym_type);
  667. oper.opr.typ:=OPR_SYMBOL;
  668. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  669. end
  670. else
  671. inc(oper.opr.val,l);
  672. OPR_SYMBOL:
  673. Message(asmr_e_invalid_symbol_ref);
  674. else
  675. internalerror(200309221);
  676. end;
  677. end;
  678. function MaybeBuildReference(is64bit: boolean):boolean;
  679. { Try to create a reference, if not a reference is found then false
  680. is returned }
  681. begin
  682. MaybeBuildReference:=true;
  683. case actasmtoken of
  684. AS_INTNUM,
  685. AS_MINUS,
  686. AS_PLUS:
  687. Begin
  688. oper.opr.ref.offset:=BuildConstExpression(True,False);
  689. if actasmtoken<>AS_LPAREN then
  690. Message(asmr_e_invalid_reference_syntax)
  691. else
  692. BuildReference(oper,is64bit);
  693. end;
  694. AS_LPAREN:
  695. BuildReference(oper,is64bit);
  696. AS_ID: { only a variable is allowed ... }
  697. Begin
  698. ReadSym(oper,is64bit);
  699. case actasmtoken of
  700. AS_end,
  701. AS_SEPARATOR,
  702. AS_COMMA: ;
  703. AS_LPAREN:
  704. BuildReference(oper,is64bit);
  705. else
  706. Begin
  707. Message(asmr_e_invalid_reference_syntax);
  708. Consume(actasmtoken);
  709. end;
  710. end; {end case }
  711. end;
  712. else
  713. MaybeBuildReference:=false;
  714. end; { end case }
  715. end;
  716. function parsereg: tregister;
  717. var
  718. subreg: tsubregister;
  719. begin
  720. result:=actasmregister;
  721. Consume(AS_REGISTER);
  722. if (actasmtoken=AS_ID) and
  723. (actasmpattern[1]='.') then
  724. begin
  725. subreg:=ParseArrangementSpecifier(upper(actasmpattern));
  726. if (subreg<>R_SUBNONE) and
  727. (getregtype(result)=R_MMREGISTER) and
  728. ((actinsmmsubreg=R_SUBNONE) or
  729. (actinsmmsubreg=subreg)) then
  730. begin
  731. setsubreg(result,subreg);
  732. { they all have to be the same }
  733. actinsmmsubreg:=subreg;
  734. end
  735. else
  736. Message1(asmr_e_invalid_arrangement,actasmpattern);
  737. Consume(AS_ID);
  738. end
  739. else if (getregtype(result)=R_MMREGISTER) then
  740. begin
  741. if actinsmmsubreg<>R_SUBNONE then
  742. begin
  743. if (getsubreg(result)=R_SUBNONE) or
  744. (getsubreg(result)=actinsmmsubreg) then
  745. setsubreg(result,actinsmmsubreg)
  746. else
  747. Message1(asmr_e_invalid_arrangement,actasmpattern);
  748. end
  749. else if getsubreg(result)=R_SUBNONE then
  750. { Vxx without an arrangement is invalid, use Qxx to specify the entire 128 bits}
  751. Message1(asmr_e_invalid_arrangement,'');
  752. end;
  753. end;
  754. var
  755. tempreg: tregister;
  756. hl: tasmlabel;
  757. icond: tasmcond;
  758. regindex: byte;
  759. Begin
  760. expr:='';
  761. case actasmtoken of
  762. AS_LBRACKET: { Memory reference or constant expression }
  763. Begin
  764. oper.InitRef;
  765. BuildReference(oper,is64bit);
  766. end;
  767. AS_LSBRACKET: { register set }
  768. begin
  769. consume(AS_LSBRACKET);
  770. oper.opr.typ:=OPR_REGSET;
  771. oper.opr.basereg:=parsereg;
  772. oper.opr.nregs:=1;
  773. while (oper.opr.nregs<4) and
  774. (actasmtoken=AS_COMMA) do
  775. begin
  776. consume(AS_COMMA);
  777. tempreg:=parsereg;
  778. if getsupreg(tempreg)<>((getsupreg(oper.opr.basereg)+oper.opr.nregs) mod 32) then
  779. Message(asmr_e_a64_invalid_regset);
  780. inc(oper.opr.nregs);
  781. end;
  782. consume(AS_RSBRACKET);
  783. if actasmtoken=AS_LBRACKET then
  784. begin
  785. consume(AS_LBRACKET);
  786. oper.opr.regsetindex:=ParseRegIndex(actasmpattern);
  787. consume(AS_INTNUM);
  788. consume(AS_RBRACKET);
  789. end
  790. else
  791. oper.opr.regsetindex:=255;
  792. if not(actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  793. Message(asmr_e_syn_operand);
  794. end;
  795. AS_HASH: { Constant expression }
  796. Begin
  797. Consume(AS_HASH);
  798. BuildConstantOperand(oper);
  799. end;
  800. (*
  801. AS_INTNUM,
  802. AS_MINUS,
  803. AS_PLUS:
  804. Begin
  805. { Constant memory offset }
  806. { This must absolutely be followed by ( }
  807. oper.InitRef;
  808. oper.opr.ref.offset:=BuildConstExpression(True,False);
  809. if actasmtoken<>AS_LPAREN then
  810. begin
  811. ofs:=oper.opr.ref.offset;
  812. BuildConstantOperand(oper);
  813. inc(oper.opr.val,ofs);
  814. end
  815. else
  816. BuildReference(oper,is64bit);
  817. end;
  818. *)
  819. AS_ID: { A constant expression, or a Variable ref. }
  820. Begin
  821. { Condition code? }
  822. icond:=ToConditionCode(actasmpattern,true);
  823. if icond<>C_None then
  824. begin
  825. oper.opr.typ:=OPR_COND;
  826. oper.opr.cc:=icond;
  827. consume(AS_ID);
  828. end
  829. else
  830. { Local Label ? }
  831. if is_locallabel(actasmpattern) then
  832. begin
  833. CreateLocalLabel(actasmpattern,hl,false);
  834. Consume(AS_ID);
  835. AddLabelOperand(hl);
  836. end
  837. else
  838. { Check for label }
  839. if SearchLabel(actasmpattern,hl,false) then
  840. begin
  841. Consume(AS_ID);
  842. AddLabelOperand(hl);
  843. end
  844. else
  845. { probably a variable or normal expression }
  846. { or a procedure (such as in CALL ID) }
  847. begin
  848. { is it a constant ? }
  849. if SearchIConstant(actasmpattern,l) then
  850. begin
  851. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  852. Message(asmr_e_invalid_operand_type);
  853. BuildConstantOperand(oper);
  854. end
  855. else
  856. begin
  857. expr:=actasmpattern;
  858. Consume(AS_ID);
  859. { typecasting? }
  860. if (actasmtoken=AS_LPAREN) and
  861. SearchType(expr,typesize) then
  862. begin
  863. oper.hastype:=true;
  864. Consume(AS_LPAREN);
  865. BuildOperand(oper,is64bit);
  866. Consume(AS_RPAREN);
  867. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  868. oper.SetSize(typesize,true);
  869. end
  870. else
  871. begin
  872. if not(oper.SetupVar(expr,false)) then
  873. Begin
  874. { look for special symbols ... }
  875. if expr= '__HIGH' then
  876. begin
  877. consume(AS_LPAREN);
  878. if not oper.setupvar('high'+actasmpattern,false) then
  879. Message1(sym_e_unknown_id,'high'+actasmpattern);
  880. consume(AS_ID);
  881. consume(AS_RPAREN);
  882. end
  883. else
  884. if expr = '__RESULT' then
  885. oper.SetUpResult
  886. else
  887. if expr = '__SELF' then
  888. oper.SetupSelf
  889. else
  890. if expr = '__OLDEBP' then
  891. oper.SetupOldEBP
  892. else
  893. Message1(sym_e_unknown_id,expr);
  894. end
  895. else if oper.opr.typ<>OPR_LOCAL then
  896. begin
  897. oper.InitRef;
  898. MaybeAddGotAddrMode;
  899. end;
  900. end;
  901. end;
  902. if actasmtoken=AS_DOT then
  903. MaybeRecordOffset;
  904. { add a constant expression? }
  905. if (actasmtoken=AS_PLUS) then
  906. begin
  907. l:=BuildConstExpression(true,false);
  908. case oper.opr.typ of
  909. OPR_CONSTANT :
  910. inc(oper.opr.val,l);
  911. OPR_LOCAL :
  912. inc(oper.opr.localsymofs,l);
  913. OPR_REFERENCE :
  914. inc(oper.opr.ref.offset,l);
  915. else
  916. internalerror(2003092005);
  917. end;
  918. end
  919. end;
  920. { Do we have a indexing reference, then parse it also }
  921. if actasmtoken=AS_LPAREN then
  922. BuildReference(oper,is64bit);
  923. end;
  924. { Register, a variable reference or a constant reference }
  925. AS_REGISTER:
  926. Begin
  927. { save the type of register used. }
  928. tempreg:=parsereg;
  929. regindex:=255;
  930. if (getregtype(tempreg)=R_MMREGISTER) and
  931. (actasmtoken=AS_LBRACKET) then
  932. begin
  933. consume(AS_LBRACKET);
  934. regindex:=ParseRegIndex(actasmpattern);
  935. consume(AS_INTNUM);
  936. consume(AS_RBRACKET);
  937. end;
  938. if actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA] then
  939. begin
  940. if (oper.opr.typ<>OPR_NONE) then
  941. Message(asmr_e_invalid_operand_type);
  942. if regindex=255 then
  943. begin
  944. oper.opr.typ:=OPR_REGISTER;
  945. oper.opr.reg:=tempreg;
  946. end
  947. else
  948. begin
  949. oper.opr.typ:=OPR_INDEXEDREG;
  950. oper.opr.indexedreg:=tempreg;
  951. oper.opr.regindex:=regindex;
  952. end;
  953. end
  954. else
  955. Message(asmr_e_syn_operand);
  956. end;
  957. AS_end,
  958. AS_SEPARATOR,
  959. AS_COMMA: ;
  960. else
  961. Begin
  962. Message(asmr_e_syn_operand);
  963. Consume(actasmtoken);
  964. end;
  965. end; { end case }
  966. end;
  967. {*****************************************************************************
  968. taarch64attreader
  969. *****************************************************************************}
  970. procedure taarch64attreader.BuildOpCode(instr: taarch64instruction);
  971. var
  972. operandnum : longint;
  973. Begin
  974. { opcode }
  975. if (actasmtoken<>AS_OPCODE) then
  976. Begin
  977. Message(asmr_e_invalid_or_missing_opcode);
  978. RecoverConsume(true);
  979. exit;
  980. end;
  981. { Fill the instr object with the current state }
  982. with instr do
  983. begin
  984. Opcode:=ActOpcode;
  985. condition:=ActCondition;
  986. oppostfix:=actoppostfix;
  987. end;
  988. Consume(AS_OPCODE);
  989. { We are reading operands, so opcode will be an AS_ID }
  990. operandnum:=1;
  991. { Zero operand opcode ? }
  992. if actasmtoken in [AS_SEPARATOR,AS_end] then
  993. begin
  994. instr.Ops:=0;
  995. exit;
  996. end;
  997. { Read the operands }
  998. repeat
  999. case actasmtoken of
  1000. AS_COMMA: { Operand delimiter }
  1001. Begin
  1002. { operandnum and not operandnum+1, because tinstruction is
  1003. one-based and taicpu is zero-based)
  1004. }
  1005. if can_be_shifter_operand(instr.opcode,operandnum) then
  1006. begin
  1007. Consume(AS_COMMA);
  1008. if not TryBuildShifterOp(instr,operandnum+1) then
  1009. Message(asmr_e_illegal_shifterop_syntax);
  1010. Inc(operandnum);
  1011. end
  1012. else
  1013. begin
  1014. if operandnum>Max_Operands then
  1015. Message(asmr_e_too_many_operands)
  1016. else
  1017. Inc(operandnum);
  1018. Consume(AS_COMMA);
  1019. end;
  1020. end;
  1021. AS_SEPARATOR,
  1022. AS_end : { End of asm operands for this opcode }
  1023. begin
  1024. break;
  1025. end;
  1026. else
  1027. begin
  1028. BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit);
  1029. instr.Ops:=operandnum;
  1030. if instr.operands[operandnum].opr.typ=OPR_REFERENCE then
  1031. if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then
  1032. Message(asmr_e_invalid_reference_syntax);
  1033. ;
  1034. end;
  1035. end; { end case }
  1036. until false;
  1037. end;
  1038. function taarch64attreader.is_asmopcode(const s: string):boolean;
  1039. const
  1040. { sorted by length so longer postfixes will match first }
  1041. postfix2strsorted : array[1..7] of string[3] = (
  1042. 'SB','SH','SW',
  1043. 'B','H','W',
  1044. 'S');
  1045. postfixsorted : array[1..7] of TOpPostfix = (
  1046. PF_SB,PF_SH,PF_SW,
  1047. PF_B,PF_H,PF_W,
  1048. PF_S);
  1049. { store replicate }
  1050. ldst14: array[boolean,boolean,'1'..'4'] of tasmop =
  1051. (((A_LD1,A_LD2,A_LD3,A_LD4),
  1052. (A_LD1R,A_LD2R,A_LD3R,A_LD4R)),
  1053. ((A_ST1,A_ST2,A_ST3,A_ST4),
  1054. (A_NONE,A_NONE,A_NONE,A_NONE)));
  1055. var
  1056. j : longint;
  1057. hs : string;
  1058. maxlen : longint;
  1059. Begin
  1060. { making s a value parameter would break other assembler readers }
  1061. hs:=s;
  1062. is_asmopcode:=false;
  1063. { clear opcode }
  1064. actopcode:=A_None;
  1065. actcondition:=C_None;
  1066. { b.cond ? }
  1067. if (length(hs)=4) and
  1068. (hs[1]='B') and
  1069. (hs[2]='.') then
  1070. begin
  1071. actopcode:=A_B;
  1072. actasmtoken:=AS_OPCODE;
  1073. actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false);
  1074. if actcondition<>C_None then
  1075. is_asmopcode:=true;
  1076. exit;
  1077. end;
  1078. (* ldN(r)/stN.size ? (shorthand for "ldN(r)/stN { Vx.size, Vy.size } ..."
  1079. supported by clang and possibly gas *)
  1080. actinsmmsubreg:=R_SUBNONE;
  1081. if (length(s)>=5) and
  1082. (((hs[1]='L') and
  1083. (hs[2]='D')) or
  1084. ((hs[1]='S') and
  1085. (hs[2]='T'))) and
  1086. (hs[3] in ['1'..'4']) and
  1087. ((hs[4]='.') or
  1088. ((hs[4]='R') and
  1089. (hs[5]='.'))) then
  1090. begin
  1091. actinsmmsubreg:=ParseArrangementSpecifier(copy(hs,4+ord(hs[4]='R'),255));
  1092. if actinsmmsubreg=R_SUBNONE then
  1093. exit;
  1094. actopcode:=ldst14[hs[1]='S',hs[4]='R',hs[3]];
  1095. actasmtoken:=AS_OPCODE;
  1096. if actopcode<>A_NONE then
  1097. is_asmopcode:=true;
  1098. exit;
  1099. end;
  1100. maxlen:=max(length(hs),7);
  1101. actopcode:=A_NONE;
  1102. for j:=maxlen downto 1 do
  1103. begin
  1104. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  1105. if actopcode<>A_NONE then
  1106. begin
  1107. actasmtoken:=AS_OPCODE;
  1108. { strip op code }
  1109. delete(hs,1,j);
  1110. break;
  1111. end;
  1112. end;
  1113. if actopcode=A_NONE then
  1114. exit;
  1115. { check for postfix }
  1116. if length(hs)>0 then
  1117. begin
  1118. for j:=low(postfixsorted) to high(postfixsorted) do
  1119. begin
  1120. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  1121. begin
  1122. actoppostfix:=postfixsorted[j];
  1123. { strip postfix }
  1124. delete(hs,1,length(postfix2strsorted[j]));
  1125. break;
  1126. end;
  1127. end;
  1128. end;
  1129. { if we stripped all postfixes, it's a valid opcode }
  1130. is_asmopcode:=length(hs)=0;
  1131. end;
  1132. procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction);
  1133. var
  1134. newopr : toprrec;
  1135. begin
  1136. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  1137. begin
  1138. newopr.typ:=OPR_SYMBOL;
  1139. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  1140. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  1141. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  1142. (instr.Operands[1].opr.ref.index<>NR_NO) or
  1143. (instr.Operands[1].opr.ref.refaddr<>addr_pic) then
  1144. Message(asmr_e_syn_operand);
  1145. instr.Operands[1].opr:=newopr;
  1146. end;
  1147. end;
  1148. procedure taarch64attreader.handleopcode;
  1149. var
  1150. instr: taarch64instruction;
  1151. begin
  1152. instr:=taarch64instruction.Create(taarch64operand);
  1153. BuildOpcode(instr);
  1154. if is_calljmp(instr.opcode) then
  1155. ConvertCalljmp(instr);
  1156. {
  1157. instr.AddReferenceSizes;
  1158. instr.SetInstructionOpsize;
  1159. instr.CheckOperandSizes;
  1160. }
  1161. instr.ConcatInstruction(curlist);
  1162. instr.Free;
  1163. actoppostfix:=PF_None;
  1164. end;
  1165. procedure taarch64attreader.handletargetdirective;
  1166. function maxoffset(ash:TAsmSehDirective):aint;
  1167. begin
  1168. case ash of
  1169. ash_savefplr,
  1170. ash_saveregp,
  1171. ash_savereg,
  1172. ash_savefregp,
  1173. ash_savefreg:
  1174. result:=504;
  1175. ash_savefplr_x,
  1176. ash_saveregp_x,
  1177. ash_savefregp_x:
  1178. result:=-512;
  1179. ash_savereg_x,
  1180. ash_savefreg_x:
  1181. result:=-256;
  1182. ash_addfp:
  1183. result:=2040;
  1184. else
  1185. internalerror(2020041204);
  1186. end;
  1187. end;
  1188. procedure add_reg_with_offset(ash:TAsmSehDirective;hreg:tregister;hnum:aint;neg:boolean);
  1189. begin
  1190. if (neg and ((hnum>0) or (hnum<maxoffset(ash)) or (((-hnum) and $7)<>0))) or
  1191. (not neg and ((hnum<0) or (hnum>maxoffset(ash)) or ((hnum and $7)<>0))) then
  1192. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[actsehdirective])
  1193. else
  1194. begin
  1195. if neg then
  1196. hnum:=-hnum;
  1197. if hreg=NR_NO then
  1198. curlist.concat(cai_seh_directive.create_offset(actsehdirective,hnum))
  1199. else
  1200. curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum));
  1201. end;
  1202. end;
  1203. var
  1204. hreg,
  1205. hreg2 : TRegister;
  1206. hnum : aint;
  1207. flags : integer;
  1208. ai : tai_seh_directive;
  1209. hs : string;
  1210. err : boolean;
  1211. begin
  1212. if actasmtoken<>AS_TARGET_DIRECTIVE then
  1213. InternalError(2020033102);
  1214. Consume(AS_TARGET_DIRECTIVE);
  1215. Include(current_procinfo.flags,pi_has_unwind_info);
  1216. case actsehdirective of
  1217. ash_nop,
  1218. ash_setfp,
  1219. ash_endprologue,
  1220. ash_handlerdata:
  1221. curlist.concat(cai_seh_directive.create(actsehdirective));
  1222. ash_handler:
  1223. begin
  1224. hs:=actasmpattern;
  1225. Consume(AS_ID);
  1226. flags:=0;
  1227. err:=false;
  1228. while actasmtoken=AS_COMMA do
  1229. begin
  1230. Consume(AS_COMMA);
  1231. if actasmtoken=AS_AT then
  1232. begin
  1233. Consume(AS_AT);
  1234. if actasmtoken=AS_ID then
  1235. begin
  1236. uppervar(actasmpattern);
  1237. if actasmpattern='EXCEPT' then
  1238. flags:=flags or 1
  1239. else if actasmpattern='UNWIND' then
  1240. flags:=flags or 2
  1241. else
  1242. err:=true;
  1243. Consume(AS_ID);
  1244. end
  1245. else
  1246. err:=true;
  1247. end
  1248. else
  1249. err:=true;
  1250. if err then
  1251. begin
  1252. Message(asmr_e_syntax_error);
  1253. RecoverConsume(false);
  1254. exit;
  1255. end;
  1256. end;
  1257. ai:=cai_seh_directive.create_name(ash_handler,hs);
  1258. ai.data.flags:=flags;
  1259. curlist.concat(ai);
  1260. end;
  1261. ash_savefplr,
  1262. ash_savefplr_x:
  1263. begin
  1264. hnum:=BuildConstExpression(false,false);
  1265. add_reg_with_offset(actsehdirective,NR_NO,hnum,actsehdirective=ash_savefplr_x);
  1266. end;
  1267. ash_savereg,
  1268. ash_savereg_x:
  1269. begin
  1270. hreg:=actasmregister;
  1271. Consume(AS_REGISTER);
  1272. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1273. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1274. Consume(AS_COMMA);
  1275. hnum:=BuildConstExpression(false,false);
  1276. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savereg_x);
  1277. end;
  1278. ash_saveregp,
  1279. ash_saveregp_x:
  1280. begin
  1281. hreg:=actasmregister;
  1282. consume(AS_REGISTER);
  1283. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1284. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1285. consume(AS_COMMA);
  1286. hreg2:=actasmregister;
  1287. consume(AS_REGISTER);
  1288. if (getregtype(hreg2)<>R_INTREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1289. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1290. consume(AS_COMMA);
  1291. hnum:=BuildConstExpression(false,false);
  1292. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_saveregp_x);
  1293. end;
  1294. ash_savefreg,
  1295. ash_savefreg_x:
  1296. begin
  1297. hreg:=actasmregister;
  1298. Consume(AS_REGISTER);
  1299. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1300. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1301. Consume(AS_COMMA);
  1302. hnum:=BuildConstExpression(false,false);
  1303. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefreg_x);
  1304. end;
  1305. ash_savefregp,
  1306. ash_savefregp_x:
  1307. begin
  1308. hreg:=actasmregister;
  1309. consume(AS_REGISTER);
  1310. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1311. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1312. consume(AS_COMMA);
  1313. hreg2:=actasmregister;
  1314. consume(AS_REGISTER);
  1315. if (getregtype(hreg2)<>R_MMREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1316. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1317. consume(AS_COMMA);
  1318. hnum:=BuildConstExpression(false,false);
  1319. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefregp_x);
  1320. end;
  1321. ash_stackalloc:
  1322. begin
  1323. hnum:=BuildConstExpression(false,false);
  1324. if (hnum<0) or (hnum>$FFFFFF) or ((hnum and 7)<>0) then
  1325. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_stackalloc])
  1326. else
  1327. curlist.concat(cai_seh_directive.create_offset(ash_stackalloc,hnum));
  1328. end;
  1329. else
  1330. InternalError(2020033103);
  1331. end;
  1332. if actasmtoken<>AS_SEPARATOR then
  1333. Consume(AS_SEPARATOR);
  1334. end;
  1335. {*****************************************************************************
  1336. Initialize
  1337. *****************************************************************************}
  1338. const
  1339. asmmode_arm_att_info : tasmmodeinfo =
  1340. (
  1341. id : asmmode_arm_gas;
  1342. idtxt : 'GAS';
  1343. casmreader : taarch64attreader;
  1344. );
  1345. asmmode_arm_standard_info : tasmmodeinfo =
  1346. (
  1347. id : asmmode_standard;
  1348. idtxt : 'STANDARD';
  1349. casmreader : taarch64attreader;
  1350. );
  1351. initialization
  1352. RegisterAsmMode(asmmode_arm_att_info);
  1353. RegisterAsmMode(asmmode_arm_standard_info);
  1354. end.