racpugas.pas 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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. cpubase;
  24. type
  25. taarch64attreader = class(tattreader)
  26. actoppostfix : TOpPostfix;
  27. function is_asmopcode(const s: string):boolean;override;
  28. function is_register(const s:string):boolean;override;
  29. procedure handleopcode;override;
  30. procedure BuildReference(oper: taarch64operand; is64bit: boolean);
  31. procedure BuildOperand(oper: taarch64operand; is64bit: boolean);
  32. function TryBuildShifterOp(instr: taarch64instruction; opnr: longint) : boolean;
  33. procedure BuildOpCode(instr: taarch64instruction);
  34. procedure ReadSym(oper: taarch64operand; is64bit: boolean);
  35. procedure ConvertCalljmp(instr: taarch64instruction);
  36. function ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  37. end;
  38. Implementation
  39. uses
  40. { helpers }
  41. cutils,
  42. { global }
  43. globtype,verbose,
  44. systems,aasmbase,aasmtai,aasmdata,aasmcpu,
  45. { symtable }
  46. symconst,symsym,symdef,
  47. procinfo,
  48. rabase,rautils,
  49. cgbase,cgutils,paramgr;
  50. function taarch64attreader.is_register(const s:string):boolean;
  51. type
  52. treg2str = record
  53. name : string[3];
  54. reg : tregister;
  55. end;
  56. const
  57. extraregs : array[0..3] of treg2str = (
  58. (name: 'FP' ; reg: NR_FP),
  59. (name: 'LR' ; reg: NR_LR),
  60. (name: 'IP0'; reg: NR_IP0),
  61. (name: 'IP1'; reg: NR_IP1));
  62. var
  63. i : longint;
  64. begin
  65. result:=inherited is_register(s);
  66. { reg found?
  67. possible aliases are always 2 or 3 chars
  68. }
  69. if result or not(length(s) in [2,3]) then
  70. exit;
  71. for i:=low(extraregs) to high(extraregs) do
  72. begin
  73. if s=extraregs[i].name then
  74. begin
  75. actasmregister:=extraregs[i].reg;
  76. result:=true;
  77. actasmtoken:=AS_REGISTER;
  78. exit;
  79. end;
  80. end;
  81. end;
  82. procedure taarch64attreader.ReadSym(oper: taarch64operand; is64bit: boolean);
  83. var
  84. tempstr, mangledname : string;
  85. typesize,l,k: aint;
  86. begin
  87. tempstr:=actasmpattern;
  88. Consume(AS_ID);
  89. { typecasting? }
  90. if (actasmtoken=AS_LPAREN) and
  91. SearchType(tempstr,typesize) then
  92. begin
  93. oper.hastype:=true;
  94. Consume(AS_LPAREN);
  95. BuildOperand(oper,is64bit);
  96. Consume(AS_RPAREN);
  97. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  98. oper.SetSize(typesize,true);
  99. end
  100. else
  101. if not oper.SetupVar(tempstr,false) then
  102. Message1(sym_e_unknown_id,tempstr);
  103. { record.field ? }
  104. if actasmtoken=AS_DOT then
  105. begin
  106. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  107. if (mangledname<>'') then
  108. Message(asmr_e_invalid_reference_syntax);
  109. inc(oper.opr.ref.offset,l);
  110. end;
  111. end;
  112. Procedure taarch64attreader.BuildReference(oper: taarch64operand; is64bit: boolean);
  113. procedure do_error;
  114. begin
  115. Message(asmr_e_invalid_reference_syntax);
  116. RecoverConsume(false);
  117. end;
  118. procedure test_end(require_rbracket : boolean);
  119. begin
  120. if require_rbracket then begin
  121. if not(actasmtoken=AS_RBRACKET) then
  122. begin
  123. do_error;
  124. exit;
  125. end
  126. else
  127. Consume(AS_RBRACKET);
  128. if (actasmtoken=AS_NOT) then
  129. begin
  130. oper.opr.ref.addressmode:=AM_PREINDEXED;
  131. Consume(AS_NOT);
  132. end;
  133. end;
  134. if not(actasmtoken in [AS_SEPARATOR,AS_end]) then
  135. do_error
  136. else
  137. begin
  138. {$IFDEF debugasmreader}
  139. writeln('TEST_end_FINAL_OK. Created the following ref:');
  140. writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm);
  141. writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode));
  142. writeln('oper.opr.ref.index=',ord(oper.opr.ref.index));
  143. writeln('oper.opr.ref.base=',ord(oper.opr.ref.base));
  144. writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex));
  145. writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode));
  146. writeln;
  147. {$endIF debugasmreader}
  148. end;
  149. end;
  150. function is_shifter_ref_operation(var a : tshiftmode) : boolean;
  151. begin
  152. a:=SM_NONE;
  153. if (actasmpattern='LSL') then
  154. a:=SM_LSL
  155. else if (actasmpattern='UXTW') then
  156. a:=SM_UXTW
  157. else if (actasmpattern='SXTW') then
  158. a:=SM_SXTW
  159. else if (actasmpattern='SXTX') then
  160. a:=SM_SXTX;
  161. is_shifter_ref_operation:=not(a=SM_NONE);
  162. end;
  163. procedure read_index_shift(require_rbracket : boolean);
  164. var
  165. shift: aint;
  166. begin
  167. case actasmtoken of
  168. AS_COMMA :
  169. begin
  170. Consume(AS_COMMA);
  171. if not(actasmtoken=AS_ID) then
  172. do_error;
  173. if is_shifter_ref_operation(oper.opr.ref.shiftmode) then
  174. begin
  175. Consume(actasmtoken);
  176. if actasmtoken=AS_HASH then
  177. begin
  178. Consume(AS_HASH);
  179. shift:=BuildConstExpression(false,true);
  180. if not(shift in [0,2+ord(is64bit)]) then
  181. do_error;
  182. oper.opr.ref.shiftimm:=shift;
  183. test_end(require_rbracket);
  184. end;
  185. end
  186. else
  187. begin
  188. do_error;
  189. exit;
  190. end;
  191. end;
  192. AS_RBRACKET :
  193. if require_rbracket then
  194. test_end(require_rbracket)
  195. else
  196. begin
  197. do_error;
  198. exit;
  199. end;
  200. AS_SEPARATOR,AS_END :
  201. if not require_rbracket then
  202. test_end(false)
  203. else
  204. do_error;
  205. else
  206. begin
  207. do_error;
  208. exit;
  209. end;
  210. end;
  211. end;
  212. procedure read_index(require_rbracket : boolean);
  213. var
  214. recname : string;
  215. o_int,s_int : aint;
  216. begin
  217. case actasmtoken of
  218. AS_REGISTER :
  219. begin
  220. if getsupreg(actasmregister)=RS_XZR then
  221. Message1(asmr_e_invalid_ref_register,actasmpattern);
  222. oper.opr.ref.index:=actasmregister;
  223. Consume(AS_REGISTER);
  224. read_index_shift(require_rbracket);
  225. exit;
  226. end;
  227. AS_HASH : // constant
  228. begin
  229. Consume(AS_HASH);
  230. (*
  231. if actasmtoken=AS_COLON then
  232. begin
  233. consume(AS_COLON);
  234. { GNU-style lower 12 bits of address of non-GOT-based
  235. access }
  236. if (actasmpattern='LO12') then
  237. begin
  238. consume(actasmtoken);
  239. consume(AS_COLON);
  240. if not oper.SetupVar(actasmpattern,false) then
  241. begin
  242. do_error;
  243. exit
  244. end;
  245. consume(AS_ID);
  246. oper.opr.ref.refaddr:=addr_??? (not gotpageoffset);
  247. end
  248. else
  249. begin
  250. do_error;
  251. exit
  252. end;
  253. end
  254. else
  255. *)
  256. begin
  257. o_int:=BuildConstExpression(false,true);
  258. inc(oper.opr.ref.offset,o_int);
  259. end;
  260. test_end(require_rbracket);
  261. exit;
  262. end;
  263. AS_ID :
  264. begin
  265. recname:=actasmpattern;
  266. Consume(AS_ID);
  267. { Apple-style got page offset }
  268. if actasmtoken=AS_AT then
  269. begin
  270. if not oper.SetupVar(recname,false) then
  271. begin
  272. do_error;
  273. exit
  274. end;
  275. consume(AS_AT);
  276. if actasmpattern='GOTPAGEOFF' then
  277. begin
  278. consume(actasmtoken);
  279. oper.opr.ref.refaddr:=addr_gotpageoffset;
  280. end
  281. else if actasmpattern='PAGEOFF' then
  282. begin
  283. consume(actasmtoken);
  284. oper.opr.ref.refaddr:=addr_pageoffset;
  285. end
  286. else
  287. begin
  288. do_error;
  289. exit
  290. end;
  291. end
  292. else
  293. begin
  294. BuildRecordOffsetSize(recname,o_int,s_int,recname,false);
  295. inc(oper.opr.ref.offset,o_int);
  296. end;
  297. test_end(require_rbracket);
  298. exit;
  299. end;
  300. AS_AT:
  301. begin
  302. do_error;
  303. exit;
  304. end;
  305. AS_RBRACKET :
  306. begin
  307. if require_rbracket then
  308. begin
  309. test_end(require_rbracket);
  310. exit;
  311. end
  312. else
  313. begin
  314. do_error; // unexpected rbracket
  315. exit;
  316. end;
  317. end;
  318. AS_SEPARATOR,AS_end :
  319. begin
  320. if not require_rbracket then
  321. begin
  322. test_end(false);
  323. exit;
  324. end
  325. else
  326. begin
  327. do_error;
  328. exit;
  329. end;
  330. end;
  331. else
  332. begin
  333. // unexpected token
  334. do_error;
  335. exit;
  336. end;
  337. end; // case
  338. end;
  339. procedure try_prepostindexed;
  340. begin
  341. Consume(AS_RBRACKET);
  342. case actasmtoken of
  343. AS_COMMA :
  344. begin // post-indexed
  345. Consume(AS_COMMA);
  346. oper.opr.ref.addressmode:=AM_POSTINDEXED;
  347. read_index(false);
  348. exit;
  349. end;
  350. AS_NOT :
  351. begin // pre-indexed
  352. Consume(AS_NOT);
  353. oper.opr.ref.addressmode:=AM_PREINDEXED;
  354. test_end(false);
  355. exit;
  356. end;
  357. else
  358. begin
  359. test_end(false);
  360. exit;
  361. end;
  362. end; // case
  363. end;
  364. begin
  365. Consume(AS_LBRACKET);
  366. oper.opr.ref.addressmode:=AM_OFFSET; // assume "neither PRE nor POST inc"
  367. if actasmtoken=AS_REGISTER then
  368. begin
  369. if getsupreg(actasmregister)=RS_XZR then
  370. Message1(asmr_e_invalid_ref_register,actasmpattern);
  371. oper.opr.ref.base:=actasmregister;
  372. Consume(AS_REGISTER);
  373. case actasmtoken of
  374. AS_RBRACKET :
  375. begin
  376. try_prepostindexed;
  377. exit;
  378. end;
  379. AS_COMMA :
  380. begin
  381. Consume(AS_COMMA);
  382. read_index(true);
  383. exit;
  384. end;
  385. else
  386. begin
  387. Message(asmr_e_invalid_reference_syntax);
  388. RecoverConsume(false);
  389. end;
  390. end;
  391. end
  392. else
  393. Begin
  394. case actasmtoken of
  395. AS_ID :
  396. begin
  397. { TODO: local variables and parameters }
  398. Message(asmr_e_invalid_reference_syntax);
  399. RecoverConsume(false);
  400. exit;
  401. end;
  402. else
  403. begin // elsecase
  404. Message(asmr_e_invalid_reference_syntax);
  405. RecoverConsume(false);
  406. exit;
  407. end;
  408. end;
  409. end;
  410. end;
  411. function taarch64attreader.TryBuildShifterOp(instr: taarch64instruction; opnr: longint): boolean;
  412. procedure handlepara(sm : tshiftmode);
  413. begin
  414. consume(AS_ID);
  415. fillchar(instr.operands[opnr].opr,sizeof(instr.operands[opnr].opr),0);
  416. instr.operands[opnr].opr.typ:=OPR_SHIFTEROP;
  417. instr.operands[opnr].opr.shifterop.shiftmode:=sm;
  418. if (sm=SM_LSL) or
  419. (actasmtoken=AS_HASH) then
  420. begin
  421. consume(AS_HASH);
  422. instr.operands[opnr].opr.shifterop.shiftimm:=BuildConstExpression(false,false);
  423. end;
  424. end;
  425. const
  426. shiftmode2str: array[SM_LSL..SM_SXTX] of string[4] =
  427. ('LSL','LSR','ASR',
  428. 'UXTB','UXTH','UXTW','UXTX',
  429. 'SXTB','SXTH','SXTW','SXTX');
  430. var
  431. sm: tshiftmode;
  432. i: longint;
  433. usessp,
  434. useszr: boolean;
  435. begin
  436. result:=false;
  437. if (actasmtoken=AS_ID) then
  438. begin
  439. for sm:=low(shiftmode2str) to high(shiftmode2str) do
  440. if actasmpattern=shiftmode2str[sm] then
  441. begin
  442. handlepara(sm);
  443. if instr.operands[1].opr.typ=OPR_REGISTER then
  444. begin
  445. { the possible shifter ops depend on whether this
  446. instruction uses sp and/or zr }
  447. usessp:=false;
  448. useszr:=false;
  449. for i:=low(instr.operands) to pred(opnr) do
  450. begin
  451. if (instr.operands[1].opr.typ=OPR_REGISTER) then
  452. case getsupreg(instr.operands[1].opr.reg) of
  453. RS_XZR:
  454. useszr:=true;
  455. RS_SP:
  456. usessp:=true;
  457. end;
  458. end;
  459. result:=valid_shifter_operand(instr.opcode,useszr,usessp,instr.Is64bit,sm,instr.operands[opnr].opr.shifterop.shiftimm);
  460. end
  461. end;
  462. end;
  463. end;
  464. function taarch64attreader.ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  465. begin
  466. case actopcode of
  467. A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM,
  468. A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP,
  469. A_B:
  470. begin
  471. { search for condition, conditions are always 2 chars }
  472. if (is_operand<>(actopcode=A_B)) and
  473. (length(hs)>1) then
  474. begin
  475. { workaround for DFA bug }
  476. result:=low(tasmcond);
  477. for result:=low(tasmcond) to high(tasmcond) do
  478. begin
  479. if hs=uppercond2str[result] then
  480. exit;
  481. end;
  482. end;
  483. end;
  484. end;
  485. result:=C_None;;
  486. end;
  487. Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean);
  488. var
  489. expr: string;
  490. typesize, l: aint;
  491. procedure MaybeAddGotAddrMode;
  492. begin
  493. if actasmtoken=AS_AT then
  494. begin
  495. consume(AS_AT);
  496. if actasmpattern='GOTPAGE' then
  497. oper.opr.ref.refaddr:=addr_gotpage
  498. else if actasmpattern='GOTPAGEOFF' then
  499. oper.opr.ref.refaddr:=addr_gotpageoffset
  500. else if actasmpattern='PAGE' then
  501. oper.opr.ref.refaddr:=addr_page
  502. else if actasmpattern='PAGEOFF' then
  503. oper.opr.ref.refaddr:=addr_pageoffset
  504. else
  505. Message(asmr_e_expr_illegal);
  506. consume(actasmtoken);
  507. end
  508. else
  509. oper.opr.ref.refaddr:=addr_pic;
  510. end;
  511. procedure AddLabelOperand(hl:tasmlabel);
  512. begin
  513. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  514. is_calljmp(actopcode) then
  515. begin
  516. oper.opr.typ:=OPR_SYMBOL;
  517. oper.opr.symbol:=hl;
  518. end
  519. else if (actopcode=A_ADR) or
  520. (actopcode=A_ADRP) then
  521. begin
  522. oper.InitRef;
  523. MaybeAddGotAddrMode;
  524. oper.opr.ref.symbol:=hl;
  525. if (actasmtoken in [AS_PLUS, AS_MINUS]) then
  526. begin
  527. l:=BuildConstExpression(true,false);
  528. oper.opr.ref.offset:=l;
  529. end;
  530. end;
  531. end;
  532. procedure MaybeRecordOffset;
  533. var
  534. mangledname: string;
  535. hasdot : boolean;
  536. l,
  537. toffset,
  538. tsize : aint;
  539. begin
  540. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  541. exit;
  542. l:=0;
  543. mangledname:='';
  544. hasdot:=(actasmtoken=AS_DOT);
  545. if hasdot then
  546. begin
  547. if expr<>'' then
  548. begin
  549. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  550. if (oper.opr.typ<>OPR_CONSTANT) and
  551. (mangledname<>'') then
  552. Message(asmr_e_wrong_sym_type);
  553. inc(l,toffset);
  554. oper.SetSize(tsize,true);
  555. end;
  556. end;
  557. if actasmtoken in [AS_PLUS,AS_MINUS] then
  558. inc(l,BuildConstExpression(true,false));
  559. case oper.opr.typ of
  560. OPR_LOCAL :
  561. begin
  562. { don't allow direct access to fields of parameters, because that
  563. will generate buggy code. Allow it only for explicit typecasting }
  564. if hasdot and
  565. (not oper.hastype) and
  566. (oper.opr.localsym.typ=paravarsym) and
  567. (not(po_assembler in current_procinfo.procdef.procoptions) or
  568. (tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
  569. (not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
  570. not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
  571. Message(asmr_e_cannot_access_field_directly_for_parameters);
  572. inc(oper.opr.localsymofs,l)
  573. end;
  574. OPR_CONSTANT :
  575. inc(oper.opr.val,l);
  576. OPR_REFERENCE :
  577. if (mangledname<>'') then
  578. begin
  579. if (oper.opr.val<>0) then
  580. Message(asmr_e_wrong_sym_type);
  581. oper.opr.typ:=OPR_SYMBOL;
  582. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  583. end
  584. else
  585. inc(oper.opr.val,l);
  586. OPR_SYMBOL:
  587. Message(asmr_e_invalid_symbol_ref);
  588. else
  589. internalerror(200309221);
  590. end;
  591. end;
  592. function MaybeBuildReference(is64bit: boolean):boolean;
  593. { Try to create a reference, if not a reference is found then false
  594. is returned }
  595. begin
  596. MaybeBuildReference:=true;
  597. case actasmtoken of
  598. AS_INTNUM,
  599. AS_MINUS,
  600. AS_PLUS:
  601. Begin
  602. oper.opr.ref.offset:=BuildConstExpression(True,False);
  603. if actasmtoken<>AS_LPAREN then
  604. Message(asmr_e_invalid_reference_syntax)
  605. else
  606. BuildReference(oper,is64bit);
  607. end;
  608. AS_LPAREN:
  609. BuildReference(oper,is64bit);
  610. AS_ID: { only a variable is allowed ... }
  611. Begin
  612. ReadSym(oper,is64bit);
  613. case actasmtoken of
  614. AS_end,
  615. AS_SEPARATOR,
  616. AS_COMMA: ;
  617. AS_LPAREN:
  618. BuildReference(oper,is64bit);
  619. else
  620. Begin
  621. Message(asmr_e_invalid_reference_syntax);
  622. Consume(actasmtoken);
  623. end;
  624. end; {end case }
  625. end;
  626. else
  627. MaybeBuildReference:=false;
  628. end; { end case }
  629. end;
  630. var
  631. tempreg: tregister;
  632. hl: tasmlabel;
  633. icond: tasmcond;
  634. Begin
  635. expr:='';
  636. case actasmtoken of
  637. AS_LBRACKET: { Memory reference or constant expression }
  638. Begin
  639. oper.InitRef;
  640. BuildReference(oper,is64bit);
  641. end;
  642. AS_HASH: { Constant expression }
  643. Begin
  644. Consume(AS_HASH);
  645. BuildConstantOperand(oper);
  646. end;
  647. (*
  648. AS_INTNUM,
  649. AS_MINUS,
  650. AS_PLUS:
  651. Begin
  652. { Constant memory offset }
  653. { This must absolutely be followed by ( }
  654. oper.InitRef;
  655. oper.opr.ref.offset:=BuildConstExpression(True,False);
  656. if actasmtoken<>AS_LPAREN then
  657. begin
  658. ofs:=oper.opr.ref.offset;
  659. BuildConstantOperand(oper);
  660. inc(oper.opr.val,ofs);
  661. end
  662. else
  663. BuildReference(oper,is64bit);
  664. end;
  665. *)
  666. AS_ID: { A constant expression, or a Variable ref. }
  667. Begin
  668. { Condition code? }
  669. icond:=ToConditionCode(actasmpattern,true);
  670. if icond<>C_None then
  671. begin
  672. oper.opr.typ:=OPR_COND;
  673. oper.opr.cc:=icond;
  674. consume(AS_ID);
  675. end
  676. else
  677. { Local Label ? }
  678. if is_locallabel(actasmpattern) then
  679. begin
  680. CreateLocalLabel(actasmpattern,hl,false);
  681. Consume(AS_ID);
  682. AddLabelOperand(hl);
  683. end
  684. else
  685. { Check for label }
  686. if SearchLabel(actasmpattern,hl,false) then
  687. begin
  688. Consume(AS_ID);
  689. AddLabelOperand(hl);
  690. end
  691. else
  692. { probably a variable or normal expression }
  693. { or a procedure (such as in CALL ID) }
  694. begin
  695. { is it a constant ? }
  696. if SearchIConstant(actasmpattern,l) then
  697. begin
  698. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  699. Message(asmr_e_invalid_operand_type);
  700. BuildConstantOperand(oper);
  701. end
  702. else
  703. begin
  704. expr:=actasmpattern;
  705. Consume(AS_ID);
  706. { typecasting? }
  707. if (actasmtoken=AS_LPAREN) and
  708. SearchType(expr,typesize) then
  709. begin
  710. oper.hastype:=true;
  711. Consume(AS_LPAREN);
  712. BuildOperand(oper,is64bit);
  713. Consume(AS_RPAREN);
  714. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  715. oper.SetSize(typesize,true);
  716. end
  717. else
  718. begin
  719. if not(oper.SetupVar(expr,false)) then
  720. Begin
  721. { look for special symbols ... }
  722. if expr= '__HIGH' then
  723. begin
  724. consume(AS_LPAREN);
  725. if not oper.setupvar('high'+actasmpattern,false) then
  726. Message1(sym_e_unknown_id,'high'+actasmpattern);
  727. consume(AS_ID);
  728. consume(AS_RPAREN);
  729. end
  730. else
  731. if expr = '__RESULT' then
  732. oper.SetUpResult
  733. else
  734. if expr = '__SELF' then
  735. oper.SetupSelf
  736. else
  737. if expr = '__OLDEBP' then
  738. oper.SetupOldEBP
  739. else
  740. Message1(sym_e_unknown_id,expr);
  741. end
  742. else
  743. MaybeAddGotAddrMode;
  744. end;
  745. end;
  746. if actasmtoken=AS_DOT then
  747. MaybeRecordOffset;
  748. { add a constant expression? }
  749. if (actasmtoken=AS_PLUS) then
  750. begin
  751. l:=BuildConstExpression(true,false);
  752. case oper.opr.typ of
  753. OPR_CONSTANT :
  754. inc(oper.opr.val,l);
  755. OPR_LOCAL :
  756. inc(oper.opr.localsymofs,l);
  757. OPR_REFERENCE :
  758. inc(oper.opr.ref.offset,l);
  759. else
  760. internalerror(200309202);
  761. end;
  762. end
  763. end;
  764. { Do we have a indexing reference, then parse it also }
  765. if actasmtoken=AS_LPAREN then
  766. BuildReference(oper,is64bit);
  767. end;
  768. { Register, a variable reference or a constant reference }
  769. AS_REGISTER:
  770. Begin
  771. { save the type of register used. }
  772. tempreg:=actasmregister;
  773. Consume(AS_REGISTER);
  774. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  775. Begin
  776. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  777. Message(asmr_e_invalid_operand_type);
  778. oper.opr.typ:=OPR_REGISTER;
  779. oper.opr.reg:=tempreg;
  780. end
  781. else
  782. Message(asmr_e_syn_operand);
  783. end;
  784. AS_end,
  785. AS_SEPARATOR,
  786. AS_COMMA: ;
  787. else
  788. Begin
  789. Message(asmr_e_syn_operand);
  790. Consume(actasmtoken);
  791. end;
  792. end; { end case }
  793. end;
  794. {*****************************************************************************
  795. taarch64attreader
  796. *****************************************************************************}
  797. procedure taarch64attreader.BuildOpCode(instr: taarch64instruction);
  798. var
  799. operandnum : longint;
  800. Begin
  801. { opcode }
  802. if (actasmtoken<>AS_OPCODE) then
  803. Begin
  804. Message(asmr_e_invalid_or_missing_opcode);
  805. RecoverConsume(true);
  806. exit;
  807. end;
  808. { Fill the instr object with the current state }
  809. with instr do
  810. begin
  811. Opcode:=ActOpcode;
  812. condition:=ActCondition;
  813. oppostfix:=actoppostfix;
  814. end;
  815. Consume(AS_OPCODE);
  816. { We are reading operands, so opcode will be an AS_ID }
  817. operandnum:=1;
  818. { Zero operand opcode ? }
  819. if actasmtoken in [AS_SEPARATOR,AS_end] then
  820. begin
  821. instr.Ops:=0;
  822. exit;
  823. end;
  824. { Read the operands }
  825. repeat
  826. case actasmtoken of
  827. AS_COMMA: { Operand delimiter }
  828. Begin
  829. { operandnum and not operandnum+1, because tinstruction is
  830. one-based and taicpu is zero-based)
  831. }
  832. if can_be_shifter_operand(instr.opcode,operandnum) then
  833. begin
  834. Consume(AS_COMMA);
  835. if not TryBuildShifterOp(instr,operandnum+1) then
  836. Message(asmr_e_illegal_shifterop_syntax);
  837. Inc(operandnum);
  838. end
  839. else
  840. begin
  841. if operandnum>Max_Operands then
  842. Message(asmr_e_too_many_operands)
  843. else
  844. Inc(operandnum);
  845. Consume(AS_COMMA);
  846. end;
  847. end;
  848. AS_SEPARATOR,
  849. AS_end : { End of asm operands for this opcode }
  850. begin
  851. break;
  852. end;
  853. else
  854. begin
  855. BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit);
  856. instr.Ops:=operandnum;
  857. if instr.operands[operandnum].opr.typ=OPR_REFERENCE then
  858. if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then
  859. Message(asmr_e_invalid_reference_syntax);
  860. ;
  861. end;
  862. end; { end case }
  863. until false;
  864. end;
  865. function taarch64attreader.is_asmopcode(const s: string):boolean;
  866. const
  867. { sorted by length so longer postfixes will match first }
  868. postfix2strsorted : array[1..7] of string[3] = (
  869. 'SB','SH','SW',
  870. 'B','H','W',
  871. 'S');
  872. postfixsorted : array[1..7] of TOpPostfix = (
  873. PF_SB,PF_SH,PF_SW,
  874. PF_B,PF_H,PF_W,
  875. PF_S);
  876. var
  877. j : longint;
  878. hs : string;
  879. maxlen : longint;
  880. icond : tasmcond;
  881. Begin
  882. { making s a value parameter would break other assembler readers }
  883. hs:=s;
  884. is_asmopcode:=false;
  885. { clear opcode }
  886. actopcode:=A_None;
  887. actcondition:=C_None;
  888. { b.cond ? }
  889. if (length(hs)=4) and
  890. (hs[1]='B') and
  891. (hs[2]='.') then
  892. begin
  893. actopcode:=A_B;
  894. actasmtoken:=AS_OPCODE;
  895. actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false);
  896. if actcondition<>C_None then
  897. is_asmopcode:=true;
  898. exit;
  899. end;
  900. maxlen:=max(length(hs),7);
  901. actopcode:=A_NONE;
  902. for j:=maxlen downto 1 do
  903. begin
  904. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  905. if actopcode<>A_NONE then
  906. begin
  907. actasmtoken:=AS_OPCODE;
  908. { strip op code }
  909. delete(hs,1,j);
  910. break;
  911. end;
  912. end;
  913. if actopcode=A_NONE then
  914. exit;
  915. { check for postfix }
  916. if length(hs)>0 then
  917. begin
  918. for j:=low(postfixsorted) to high(postfixsorted) do
  919. begin
  920. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  921. begin
  922. actoppostfix:=postfixsorted[j];
  923. { strip postfix }
  924. delete(hs,1,length(postfix2strsorted[j]));
  925. break;
  926. end;
  927. end;
  928. end;
  929. { if we stripped all postfixes, it's a valid opcode }
  930. is_asmopcode:=length(hs)=0;
  931. end;
  932. procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction);
  933. var
  934. newopr : toprrec;
  935. begin
  936. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  937. begin
  938. newopr.typ:=OPR_SYMBOL;
  939. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  940. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  941. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  942. (instr.Operands[1].opr.ref.index<>NR_NO) or
  943. (instr.Operands[1].opr.ref.refaddr<>addr_pic) then
  944. Message(asmr_e_syn_operand);
  945. instr.Operands[1].opr:=newopr;
  946. end;
  947. end;
  948. procedure taarch64attreader.handleopcode;
  949. var
  950. instr: taarch64instruction;
  951. begin
  952. instr:=taarch64instruction.Create(taarch64operand);
  953. BuildOpcode(instr);
  954. if is_calljmp(instr.opcode) then
  955. ConvertCalljmp(instr);
  956. {
  957. instr.AddReferenceSizes;
  958. instr.SetInstructionOpsize;
  959. instr.CheckOperandSizes;
  960. }
  961. instr.ConcatInstruction(curlist);
  962. instr.Free;
  963. actoppostfix:=PF_None;
  964. end;
  965. {*****************************************************************************
  966. Initialize
  967. *****************************************************************************}
  968. const
  969. asmmode_arm_att_info : tasmmodeinfo =
  970. (
  971. id : asmmode_arm_gas;
  972. idtxt : 'GAS';
  973. casmreader : taarch64attreader;
  974. );
  975. asmmode_arm_standard_info : tasmmodeinfo =
  976. (
  977. id : asmmode_standard;
  978. idtxt : 'STANDARD';
  979. casmreader : taarch64attreader;
  980. );
  981. initialization
  982. RegisterAsmMode(asmmode_arm_att_info);
  983. RegisterAsmMode(asmmode_arm_standard_info);
  984. end.