racpugas.pas 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486
  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. {$push}{$j-}
  514. const
  515. extracond2str: array[C_HS..C_LO] of string[2] = ('CS','CC');
  516. {$pop}
  517. begin
  518. case actopcode of
  519. A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM,
  520. A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP,
  521. A_FCCMP,A_FCCMPE,
  522. A_B:
  523. begin
  524. { search for condition, conditions are always 2 chars }
  525. if (is_operand<>(actopcode=A_B)) and
  526. (length(hs)>1) then
  527. begin
  528. { workaround for DFA bug }
  529. result:=low(tasmcond);
  530. for result:=low(uppercond2str) to high(uppercond2str) do
  531. begin
  532. if hs=uppercond2str[result] then
  533. exit;
  534. end;
  535. for result:=low(extracond2str) to high(extracond2str) do
  536. begin
  537. if hs=extracond2str[result] then
  538. exit;
  539. end;
  540. end;
  541. end;
  542. else
  543. ;
  544. end;
  545. result:=C_None;
  546. end;
  547. function taarch64attreader.ParseArrangementSpecifier(const hs: string): TSubRegister;
  548. {$push}{$j-}
  549. const
  550. arrangements: array[R_SUBMM8B..R_SUBMM2D] of string[4] =
  551. ('.8B','.16B','.4H','.8H','.2S','.4S','.1D','.2D');
  552. {$pop}
  553. begin
  554. if length(hs)>2 then
  555. begin
  556. for result:=low(arrangements) to high(arrangements) do
  557. if hs=arrangements[result] then
  558. exit;
  559. result:=R_SUBNONE;
  560. end
  561. else
  562. case hs of
  563. '.B': result:=R_SUBMMB1;
  564. '.H': result:=R_SUBMMH1;
  565. '.S': result:=R_SUBMMS1;
  566. '.D': result:=R_SUBMMD1;
  567. else
  568. result:=R_SUBNONE;
  569. end
  570. end;
  571. function taarch64attreader.ParseRegIndex(const hs: string): byte;
  572. var
  573. b: cardinal;
  574. error: longint;
  575. begin
  576. b:=0;
  577. val(hs,b,error);
  578. if (error<>0) then
  579. Message(asmr_e_syn_constant)
  580. else if b > 31 then
  581. begin
  582. Message(asmr_e_constant_out_of_bounds);
  583. b:=0;
  584. end;
  585. result:=b;
  586. end;
  587. Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean);
  588. var
  589. expr: string;
  590. typesize, l: aint;
  591. procedure MaybeAddGotAddrMode;
  592. begin
  593. if actasmtoken=AS_AT then
  594. begin
  595. consume(AS_AT);
  596. if actasmpattern='GOTPAGE' then
  597. oper.opr.ref.refaddr:=addr_gotpage
  598. else if actasmpattern='GOTPAGEOFF' then
  599. oper.opr.ref.refaddr:=addr_gotpageoffset
  600. else if actasmpattern='PAGE' then
  601. oper.opr.ref.refaddr:=addr_page
  602. else if actasmpattern='PAGEOFF' then
  603. oper.opr.ref.refaddr:=addr_pageoffset
  604. else
  605. Message(asmr_e_expr_illegal);
  606. consume(actasmtoken);
  607. end
  608. else
  609. oper.opr.ref.refaddr:=addr_pic;
  610. end;
  611. procedure AddLabelOperand(hl:tasmlabel);
  612. begin
  613. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  614. is_calljmp(actopcode) then
  615. begin
  616. oper.opr.typ:=OPR_SYMBOL;
  617. oper.opr.symbol:=hl;
  618. end
  619. else if (actopcode=A_ADR) or
  620. (actopcode=A_ADRP) or
  621. (actopcode=A_LDR) then
  622. begin
  623. oper.InitRef;
  624. MaybeAddGotAddrMode;
  625. oper.opr.ref.symbol:=hl;
  626. if (actasmtoken in [AS_PLUS, AS_MINUS]) then
  627. begin
  628. l:=BuildConstExpression(true,false);
  629. oper.opr.ref.offset:=l;
  630. end;
  631. end;
  632. end;
  633. procedure MaybeRecordOffset;
  634. var
  635. mangledname: string;
  636. hasdot : boolean;
  637. l,
  638. toffset,
  639. tsize : aint;
  640. begin
  641. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  642. exit;
  643. l:=0;
  644. mangledname:='';
  645. hasdot:=(actasmtoken=AS_DOT);
  646. if hasdot then
  647. begin
  648. if expr<>'' then
  649. begin
  650. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  651. if (oper.opr.typ<>OPR_CONSTANT) and
  652. (mangledname<>'') then
  653. Message(asmr_e_wrong_sym_type);
  654. inc(l,toffset);
  655. oper.SetSize(tsize,true);
  656. end;
  657. end;
  658. if actasmtoken in [AS_PLUS,AS_MINUS] then
  659. inc(l,BuildConstExpression(true,false));
  660. case oper.opr.typ of
  661. OPR_LOCAL :
  662. begin
  663. { don't allow direct access to fields of parameters, because that
  664. will generate buggy code. Allow it only for explicit typecasting }
  665. if hasdot and
  666. (not oper.hastype) then
  667. checklocalsubscript(oper.opr.localsym);
  668. inc(oper.opr.localsymofs,l)
  669. end;
  670. OPR_CONSTANT :
  671. inc(oper.opr.val,l);
  672. OPR_REFERENCE :
  673. if (mangledname<>'') then
  674. begin
  675. if (oper.opr.val<>0) then
  676. Message(asmr_e_wrong_sym_type);
  677. oper.opr.typ:=OPR_SYMBOL;
  678. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  679. end
  680. else
  681. inc(oper.opr.val,l);
  682. OPR_SYMBOL:
  683. Message(asmr_e_invalid_symbol_ref);
  684. else
  685. internalerror(200309221);
  686. end;
  687. end;
  688. function MaybeBuildReference(is64bit: boolean):boolean;
  689. { Try to create a reference, if not a reference is found then false
  690. is returned }
  691. begin
  692. MaybeBuildReference:=true;
  693. case actasmtoken of
  694. AS_INTNUM,
  695. AS_MINUS,
  696. AS_PLUS:
  697. Begin
  698. oper.opr.ref.offset:=BuildConstExpression(True,False);
  699. if actasmtoken<>AS_LPAREN then
  700. Message(asmr_e_invalid_reference_syntax)
  701. else
  702. BuildReference(oper,is64bit);
  703. end;
  704. AS_LPAREN:
  705. BuildReference(oper,is64bit);
  706. AS_ID: { only a variable is allowed ... }
  707. Begin
  708. ReadSym(oper,is64bit);
  709. case actasmtoken of
  710. AS_end,
  711. AS_SEPARATOR,
  712. AS_COMMA: ;
  713. AS_LPAREN:
  714. BuildReference(oper,is64bit);
  715. else
  716. Begin
  717. Message(asmr_e_invalid_reference_syntax);
  718. Consume(actasmtoken);
  719. end;
  720. end; {end case }
  721. end;
  722. else
  723. MaybeBuildReference:=false;
  724. end; { end case }
  725. end;
  726. function parsereg: tregister;
  727. var
  728. subreg: tsubregister;
  729. begin
  730. result:=actasmregister;
  731. Consume(AS_REGISTER);
  732. if (actasmtoken=AS_ID) and
  733. (actasmpattern[1]='.') then
  734. begin
  735. subreg:=ParseArrangementSpecifier(upper(actasmpattern));
  736. if (subreg<>R_SUBNONE) and
  737. (getregtype(result)=R_MMREGISTER) then
  738. begin
  739. if ((actinsmmsubreg=R_SUBNONE) or
  740. (actinsmmsubreg=subreg)) then
  741. begin
  742. setsubreg(result,subreg);
  743. { they all have to be the same }
  744. actinsmmsubreg:=subreg;
  745. end
  746. else if (actopcode=A_SHRN) or (actopcode=A_SHRN2) then
  747. begin
  748. { shrn, shrn2 allow combinations of different sizes ]}
  749. setsubreg(result,subreg);
  750. end
  751. else
  752. Message1(asmr_e_invalid_arrangement,actasmpattern);
  753. end
  754. else
  755. Message1(asmr_e_invalid_arrangement,actasmpattern);
  756. Consume(AS_ID);
  757. end
  758. else if (getregtype(result)=R_MMREGISTER) then
  759. begin
  760. if actinsmmsubreg<>R_SUBNONE then
  761. begin
  762. if (getsubreg(result)=R_SUBNONE) or
  763. (getsubreg(result)=actinsmmsubreg) then
  764. setsubreg(result,actinsmmsubreg)
  765. else
  766. Message1(asmr_e_invalid_arrangement,actasmpattern);
  767. end
  768. else if getsubreg(result)=R_SUBNONE then
  769. { Vxx without an arrangement is invalid, use Qxx to specify the entire 128 bits}
  770. Message1(asmr_e_invalid_arrangement,'');
  771. end;
  772. end;
  773. var
  774. tempreg: tregister;
  775. hl: tasmlabel;
  776. icond: tasmcond;
  777. regindex: byte;
  778. Begin
  779. expr:='';
  780. case actasmtoken of
  781. AS_LBRACKET: { Memory reference or constant expression }
  782. Begin
  783. oper.InitRef;
  784. BuildReference(oper,is64bit);
  785. end;
  786. AS_LSBRACKET: { register set }
  787. begin
  788. consume(AS_LSBRACKET);
  789. oper.opr.typ:=OPR_REGSET;
  790. oper.opr.basereg:=parsereg;
  791. oper.opr.nregs:=1;
  792. while (actasmtoken<>AS_RSBRACKET) and (oper.opr.nregs<4) do
  793. begin
  794. if actasmtoken=AS_MINUS then
  795. begin
  796. consume(AS_MINUS);
  797. tempreg:=parsereg;
  798. if (getsupreg(tempreg)-getsupreg(oper.opr.basereg))>=4 then
  799. Message(asmr_e_a64_regset_too_large);
  800. oper.opr.nregs:=getsupreg(tempreg)-getsupreg(oper.opr.basereg)+1;
  801. if actasmtoken<>AS_COMMA then
  802. break;
  803. end;
  804. if actasmtoken=AS_COMMA then
  805. begin
  806. consume(AS_COMMA);
  807. tempreg:=parsereg;
  808. if (getsupreg(tempreg)-getsupreg(oper.opr.basereg))>=4 then
  809. Message(asmr_e_a64_regset_too_large);
  810. if getsupreg(tempreg)<>((getsupreg(oper.opr.basereg)+oper.opr.nregs) mod 32) then
  811. Message(asmr_e_a64_invalid_regset);
  812. inc(oper.opr.nregs);
  813. end
  814. else
  815. break;
  816. end;
  817. consume(AS_RSBRACKET);
  818. if actasmtoken=AS_LBRACKET then
  819. begin
  820. consume(AS_LBRACKET);
  821. oper.opr.regsetindex:=ParseRegIndex(actasmpattern);
  822. consume(AS_INTNUM);
  823. consume(AS_RBRACKET);
  824. end
  825. else
  826. oper.opr.regsetindex:=255;
  827. if not(actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  828. Message(asmr_e_syn_operand);
  829. end;
  830. AS_HASH: { Constant expression }
  831. Begin
  832. Consume(AS_HASH);
  833. BuildConstantOperand(oper);
  834. end;
  835. (*
  836. AS_INTNUM,
  837. AS_MINUS,
  838. AS_PLUS:
  839. Begin
  840. { Constant memory offset }
  841. { This must absolutely be followed by ( }
  842. oper.InitRef;
  843. oper.opr.ref.offset:=BuildConstExpression(True,False);
  844. if actasmtoken<>AS_LPAREN then
  845. begin
  846. ofs:=oper.opr.ref.offset;
  847. BuildConstantOperand(oper);
  848. inc(oper.opr.val,ofs);
  849. end
  850. else
  851. BuildReference(oper,is64bit);
  852. end;
  853. *)
  854. AS_ID: { A constant expression, or a Variable ref. }
  855. Begin
  856. { Condition code? }
  857. icond:=ToConditionCode(actasmpattern,true);
  858. if icond<>C_None then
  859. begin
  860. oper.opr.typ:=OPR_COND;
  861. oper.opr.cc:=icond;
  862. consume(AS_ID);
  863. end
  864. else
  865. { Local Label ? }
  866. if is_locallabel(actasmpattern) then
  867. begin
  868. CreateLocalLabel(actasmpattern,hl,false);
  869. Consume(AS_ID);
  870. AddLabelOperand(hl);
  871. end
  872. else
  873. { Check for label }
  874. if SearchLabel(actasmpattern,hl,false) then
  875. begin
  876. Consume(AS_ID);
  877. AddLabelOperand(hl);
  878. end
  879. else
  880. { probably a variable or normal expression }
  881. { or a procedure (such as in CALL ID) }
  882. begin
  883. { is it a constant ? }
  884. if SearchIConstant(actasmpattern,l) then
  885. begin
  886. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  887. Message(asmr_e_invalid_operand_type);
  888. BuildConstantOperand(oper);
  889. end
  890. else
  891. begin
  892. expr:=actasmpattern;
  893. Consume(AS_ID);
  894. { typecasting? }
  895. if (actasmtoken=AS_LPAREN) and
  896. SearchType(expr,typesize) then
  897. begin
  898. oper.hastype:=true;
  899. Consume(AS_LPAREN);
  900. BuildOperand(oper,is64bit);
  901. Consume(AS_RPAREN);
  902. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  903. oper.SetSize(typesize,true);
  904. end
  905. else
  906. begin
  907. if not(oper.SetupVar(expr,false)) then
  908. Begin
  909. { look for special symbols ... }
  910. if expr= '__HIGH' then
  911. begin
  912. consume(AS_LPAREN);
  913. if not oper.setupvar('high'+actasmpattern,false) then
  914. Message1(sym_e_unknown_id,'high'+actasmpattern);
  915. consume(AS_ID);
  916. consume(AS_RPAREN);
  917. end
  918. else
  919. if expr = '__RESULT' then
  920. oper.SetUpResult
  921. else
  922. if expr = '__SELF' then
  923. oper.SetupSelf
  924. else
  925. if expr = '__OLDEBP' then
  926. oper.SetupOldEBP
  927. else
  928. Message1(sym_e_unknown_id,expr);
  929. end
  930. else if oper.opr.typ<>OPR_LOCAL then
  931. begin
  932. oper.InitRef;
  933. MaybeAddGotAddrMode;
  934. end;
  935. end;
  936. end;
  937. if actasmtoken=AS_DOT then
  938. MaybeRecordOffset;
  939. { add a constant expression? }
  940. if (actasmtoken=AS_PLUS) then
  941. begin
  942. l:=BuildConstExpression(true,false);
  943. case oper.opr.typ of
  944. OPR_CONSTANT :
  945. inc(oper.opr.val,l);
  946. OPR_LOCAL :
  947. inc(oper.opr.localsymofs,l);
  948. OPR_REFERENCE :
  949. inc(oper.opr.ref.offset,l);
  950. else
  951. internalerror(2003092005);
  952. end;
  953. end
  954. end;
  955. { Do we have a indexing reference, then parse it also }
  956. if actasmtoken=AS_LPAREN then
  957. BuildReference(oper,is64bit);
  958. end;
  959. { Register, a variable reference or a constant reference }
  960. AS_REGISTER:
  961. Begin
  962. { save the type of register used. }
  963. tempreg:=parsereg;
  964. regindex:=255;
  965. if (getregtype(tempreg)=R_MMREGISTER) and
  966. (actasmtoken=AS_LBRACKET) then
  967. begin
  968. consume(AS_LBRACKET);
  969. regindex:=ParseRegIndex(actasmpattern);
  970. consume(AS_INTNUM);
  971. consume(AS_RBRACKET);
  972. end;
  973. if actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA] then
  974. begin
  975. if (oper.opr.typ<>OPR_NONE) then
  976. Message(asmr_e_invalid_operand_type);
  977. if regindex=255 then
  978. begin
  979. oper.opr.typ:=OPR_REGISTER;
  980. oper.opr.reg:=tempreg;
  981. end
  982. else
  983. begin
  984. oper.opr.typ:=OPR_INDEXEDREG;
  985. oper.opr.indexedreg:=tempreg;
  986. oper.opr.regindex:=regindex;
  987. end;
  988. end
  989. else
  990. Message(asmr_e_syn_operand);
  991. end;
  992. AS_end,
  993. AS_SEPARATOR,
  994. AS_COMMA: ;
  995. else
  996. Begin
  997. Message(asmr_e_syn_operand);
  998. Consume(actasmtoken);
  999. end;
  1000. end; { end case }
  1001. end;
  1002. {*****************************************************************************
  1003. taarch64attreader
  1004. *****************************************************************************}
  1005. procedure taarch64attreader.BuildOpCode(instr: taarch64instruction);
  1006. var
  1007. operandnum : longint;
  1008. Begin
  1009. { opcode }
  1010. if (actasmtoken<>AS_OPCODE) then
  1011. Begin
  1012. Message(asmr_e_invalid_or_missing_opcode);
  1013. RecoverConsume(true);
  1014. exit;
  1015. end;
  1016. { Fill the instr object with the current state }
  1017. with instr do
  1018. begin
  1019. Opcode:=ActOpcode;
  1020. condition:=ActCondition;
  1021. oppostfix:=actoppostfix;
  1022. end;
  1023. Consume(AS_OPCODE);
  1024. { We are reading operands, so opcode will be an AS_ID }
  1025. operandnum:=1;
  1026. { Zero operand opcode ? }
  1027. if actasmtoken in [AS_SEPARATOR,AS_end] then
  1028. begin
  1029. instr.Ops:=0;
  1030. exit;
  1031. end;
  1032. { Read the operands }
  1033. repeat
  1034. case actasmtoken of
  1035. AS_COMMA: { Operand delimiter }
  1036. Begin
  1037. { operandnum and not operandnum+1, because tinstruction is
  1038. one-based and taicpu is zero-based)
  1039. }
  1040. if can_be_shifter_operand(instr.opcode,operandnum) then
  1041. begin
  1042. Consume(AS_COMMA);
  1043. if not TryBuildShifterOp(instr,operandnum+1) then
  1044. Message(asmr_e_illegal_shifterop_syntax);
  1045. Inc(operandnum);
  1046. end
  1047. else
  1048. begin
  1049. if operandnum>Max_Operands then
  1050. Message(asmr_e_too_many_operands)
  1051. else
  1052. Inc(operandnum);
  1053. Consume(AS_COMMA);
  1054. end;
  1055. end;
  1056. AS_SEPARATOR,
  1057. AS_end : { End of asm operands for this opcode }
  1058. begin
  1059. break;
  1060. end;
  1061. else
  1062. begin
  1063. BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit);
  1064. instr.Ops:=operandnum;
  1065. if instr.operands[operandnum].opr.typ=OPR_REFERENCE then
  1066. if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then
  1067. Message(asmr_e_invalid_reference_syntax);
  1068. ;
  1069. end;
  1070. end; { end case }
  1071. until false;
  1072. end;
  1073. function taarch64attreader.is_asmopcode(const s: string):boolean;
  1074. const
  1075. { sorted by length so longer postfixes will match first }
  1076. postfix2strsorted : array[1..7] of string[3] = (
  1077. 'SB','SH','SW',
  1078. 'B','H','W',
  1079. 'S');
  1080. postfixsorted : array[1..7] of TOpPostfix = (
  1081. PF_SB,PF_SH,PF_SW,
  1082. PF_B,PF_H,PF_W,
  1083. PF_S);
  1084. { store replicate }
  1085. ldst14: array[boolean,boolean,'1'..'4'] of tasmop =
  1086. (((A_LD1,A_LD2,A_LD3,A_LD4),
  1087. (A_LD1R,A_LD2R,A_LD3R,A_LD4R)),
  1088. ((A_ST1,A_ST2,A_ST3,A_ST4),
  1089. (A_NONE,A_NONE,A_NONE,A_NONE)));
  1090. var
  1091. j : longint;
  1092. hs : string;
  1093. maxlen : longint;
  1094. Begin
  1095. { making s a value parameter would break other assembler readers }
  1096. hs:=s;
  1097. is_asmopcode:=false;
  1098. { clear opcode }
  1099. actopcode:=A_None;
  1100. actcondition:=C_None;
  1101. { b.cond ? }
  1102. if (length(hs)=4) and
  1103. (hs[1]='B') and
  1104. (hs[2]='.') then
  1105. begin
  1106. actopcode:=A_B;
  1107. actasmtoken:=AS_OPCODE;
  1108. actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false);
  1109. if actcondition<>C_None then
  1110. is_asmopcode:=true;
  1111. exit;
  1112. end;
  1113. (* ldN(r)/stN.size ? (shorthand for "ldN(r)/stN { Vx.size, Vy.size } ..."
  1114. supported by clang and possibly gas *)
  1115. actinsmmsubreg:=R_SUBNONE;
  1116. if (length(s)>=5) and
  1117. (((hs[1]='L') and
  1118. (hs[2]='D')) or
  1119. ((hs[1]='S') and
  1120. (hs[2]='T'))) and
  1121. (hs[3] in ['1'..'4']) and
  1122. ((hs[4]='.') or
  1123. ((hs[4]='R') and
  1124. (hs[5]='.'))) then
  1125. begin
  1126. actinsmmsubreg:=ParseArrangementSpecifier(copy(hs,4+ord(hs[4]='R'),255));
  1127. if actinsmmsubreg=R_SUBNONE then
  1128. exit;
  1129. actopcode:=ldst14[hs[1]='S',hs[4]='R',hs[3]];
  1130. actasmtoken:=AS_OPCODE;
  1131. if actopcode<>A_NONE then
  1132. is_asmopcode:=true;
  1133. exit;
  1134. end;
  1135. maxlen:=max(length(hs),7);
  1136. actopcode:=A_NONE;
  1137. for j:=maxlen downto 1 do
  1138. begin
  1139. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  1140. if actopcode<>A_NONE then
  1141. begin
  1142. actasmtoken:=AS_OPCODE;
  1143. { strip op code }
  1144. delete(hs,1,j);
  1145. break;
  1146. end;
  1147. end;
  1148. if actopcode=A_NONE then
  1149. exit;
  1150. { check for postfix }
  1151. if length(hs)>0 then
  1152. begin
  1153. for j:=low(postfixsorted) to high(postfixsorted) do
  1154. begin
  1155. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  1156. begin
  1157. actoppostfix:=postfixsorted[j];
  1158. { strip postfix }
  1159. delete(hs,1,length(postfix2strsorted[j]));
  1160. break;
  1161. end;
  1162. end;
  1163. end;
  1164. { if we stripped all postfixes, it's a valid opcode }
  1165. is_asmopcode:=length(hs)=0;
  1166. end;
  1167. procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction);
  1168. var
  1169. newopr : toprrec;
  1170. begin
  1171. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  1172. begin
  1173. newopr.typ:=OPR_SYMBOL;
  1174. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  1175. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  1176. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  1177. (instr.Operands[1].opr.ref.index<>NR_NO) or
  1178. (instr.Operands[1].opr.ref.refaddr<>addr_pic) then
  1179. Message(asmr_e_syn_operand);
  1180. instr.Operands[1].opr:=newopr;
  1181. end;
  1182. end;
  1183. procedure taarch64attreader.handleopcode;
  1184. var
  1185. instr: taarch64instruction;
  1186. begin
  1187. instr:=taarch64instruction.Create(taarch64operand);
  1188. BuildOpcode(instr);
  1189. if is_calljmp(instr.opcode) then
  1190. ConvertCalljmp(instr);
  1191. {
  1192. instr.AddReferenceSizes;
  1193. instr.SetInstructionOpsize;
  1194. instr.CheckOperandSizes;
  1195. }
  1196. instr.ConcatInstruction(curlist);
  1197. instr.Free;
  1198. actoppostfix:=PF_None;
  1199. end;
  1200. procedure taarch64attreader.handletargetdirective;
  1201. function maxoffset(ash:TAsmSehDirective):aint;
  1202. begin
  1203. case ash of
  1204. ash_savefplr,
  1205. ash_saveregp,
  1206. ash_savereg,
  1207. ash_savefregp,
  1208. ash_savefreg:
  1209. result:=504;
  1210. ash_savefplr_x,
  1211. ash_saveregp_x,
  1212. ash_savefregp_x:
  1213. result:=-512;
  1214. ash_savereg_x,
  1215. ash_savefreg_x:
  1216. result:=-256;
  1217. ash_addfp:
  1218. result:=2040;
  1219. else
  1220. internalerror(2020041204);
  1221. end;
  1222. end;
  1223. procedure add_reg_with_offset(ash:TAsmSehDirective;hreg:tregister;hnum:aint;neg:boolean);
  1224. begin
  1225. if (neg and ((hnum>0) or (hnum<maxoffset(ash)) or (((-hnum) and $7)<>0))) or
  1226. (not neg and ((hnum<0) or (hnum>maxoffset(ash)) or ((hnum and $7)<>0))) then
  1227. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[actsehdirective])
  1228. else
  1229. begin
  1230. if neg then
  1231. hnum:=-hnum;
  1232. if hreg=NR_NO then
  1233. curlist.concat(cai_seh_directive.create_offset(actsehdirective,hnum))
  1234. else
  1235. curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum));
  1236. end;
  1237. end;
  1238. var
  1239. hreg,
  1240. hreg2 : TRegister;
  1241. hnum : aint;
  1242. flags : integer;
  1243. ai : tai_seh_directive;
  1244. hs : string;
  1245. err : boolean;
  1246. begin
  1247. if actasmtoken<>AS_TARGET_DIRECTIVE then
  1248. InternalError(2020033102);
  1249. Consume(AS_TARGET_DIRECTIVE);
  1250. Include(current_procinfo.flags,pi_has_unwind_info);
  1251. case actsehdirective of
  1252. ash_nop,
  1253. ash_setfp,
  1254. ash_endprologue,
  1255. ash_handlerdata:
  1256. curlist.concat(cai_seh_directive.create(actsehdirective));
  1257. ash_handler:
  1258. begin
  1259. hs:=actasmpattern;
  1260. Consume(AS_ID);
  1261. flags:=0;
  1262. err:=false;
  1263. while actasmtoken=AS_COMMA do
  1264. begin
  1265. Consume(AS_COMMA);
  1266. if actasmtoken=AS_AT then
  1267. begin
  1268. Consume(AS_AT);
  1269. if actasmtoken=AS_ID then
  1270. begin
  1271. uppervar(actasmpattern);
  1272. if actasmpattern='EXCEPT' then
  1273. flags:=flags or 1
  1274. else if actasmpattern='UNWIND' then
  1275. flags:=flags or 2
  1276. else
  1277. err:=true;
  1278. Consume(AS_ID);
  1279. end
  1280. else
  1281. err:=true;
  1282. end
  1283. else
  1284. err:=true;
  1285. if err then
  1286. begin
  1287. Message(asmr_e_syntax_error);
  1288. RecoverConsume(false);
  1289. exit;
  1290. end;
  1291. end;
  1292. ai:=cai_seh_directive.create_name(ash_handler,hs);
  1293. ai.data.flags:=flags;
  1294. curlist.concat(ai);
  1295. end;
  1296. ash_savefplr,
  1297. ash_savefplr_x:
  1298. begin
  1299. hnum:=BuildConstExpression(false,false);
  1300. add_reg_with_offset(actsehdirective,NR_NO,hnum,actsehdirective=ash_savefplr_x);
  1301. end;
  1302. ash_savereg,
  1303. ash_savereg_x:
  1304. begin
  1305. hreg:=actasmregister;
  1306. Consume(AS_REGISTER);
  1307. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1308. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1309. Consume(AS_COMMA);
  1310. hnum:=BuildConstExpression(false,false);
  1311. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savereg_x);
  1312. end;
  1313. ash_saveregp,
  1314. ash_saveregp_x:
  1315. begin
  1316. hreg:=actasmregister;
  1317. consume(AS_REGISTER);
  1318. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1319. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1320. consume(AS_COMMA);
  1321. hreg2:=actasmregister;
  1322. consume(AS_REGISTER);
  1323. if (getregtype(hreg2)<>R_INTREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1324. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1325. consume(AS_COMMA);
  1326. hnum:=BuildConstExpression(false,false);
  1327. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_saveregp_x);
  1328. end;
  1329. ash_savefreg,
  1330. ash_savefreg_x:
  1331. begin
  1332. hreg:=actasmregister;
  1333. Consume(AS_REGISTER);
  1334. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1335. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1336. Consume(AS_COMMA);
  1337. hnum:=BuildConstExpression(false,false);
  1338. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefreg_x);
  1339. end;
  1340. ash_savefregp,
  1341. ash_savefregp_x:
  1342. begin
  1343. hreg:=actasmregister;
  1344. consume(AS_REGISTER);
  1345. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1346. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1347. consume(AS_COMMA);
  1348. hreg2:=actasmregister;
  1349. consume(AS_REGISTER);
  1350. if (getregtype(hreg2)<>R_MMREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1351. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1352. consume(AS_COMMA);
  1353. hnum:=BuildConstExpression(false,false);
  1354. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefregp_x);
  1355. end;
  1356. ash_stackalloc:
  1357. begin
  1358. hnum:=BuildConstExpression(false,false);
  1359. if (hnum<0) or (hnum>$FFFFFF) or ((hnum and 7)<>0) then
  1360. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_stackalloc])
  1361. else
  1362. curlist.concat(cai_seh_directive.create_offset(ash_stackalloc,hnum));
  1363. end;
  1364. else
  1365. InternalError(2020033103);
  1366. end;
  1367. if actasmtoken<>AS_SEPARATOR then
  1368. Consume(AS_SEPARATOR);
  1369. end;
  1370. {*****************************************************************************
  1371. Initialize
  1372. *****************************************************************************}
  1373. const
  1374. asmmode_arm_att_info : tasmmodeinfo =
  1375. (
  1376. id : asmmode_arm_gas;
  1377. idtxt : 'GAS';
  1378. casmreader : taarch64attreader;
  1379. );
  1380. asmmode_arm_standard_info : tasmmodeinfo =
  1381. (
  1382. id : asmmode_standard;
  1383. idtxt : 'STANDARD';
  1384. casmreader : taarch64attreader;
  1385. );
  1386. initialization
  1387. RegisterAsmMode(asmmode_arm_att_info);
  1388. RegisterAsmMode(asmmode_arm_standard_info);
  1389. end.