racpugas.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. {
  2. Copyright (c) 1998-2002 by Mazen NEIFER
  3. Does the parsing for the i386 GNU AS styled inline assembler.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. Unit racpugas;
  18. {$i fpcdefs.inc}
  19. Interface
  20. uses
  21. raatt,racpu;
  22. type
  23. tSparcReader = class(tattreader)
  24. function is_asmopcode(const s: string):boolean;override;
  25. procedure handleopcode;override;
  26. procedure BuildReference(oper : tSparcoperand);
  27. procedure BuildOperand(oper : tSparcoperand);
  28. procedure BuildOpCode(instr : tSparcinstruction);
  29. procedure ReadPercent(oper : tSparcoperand);
  30. procedure ReadSym(oper : tSparcoperand);
  31. procedure ConvertCalljmp(instr : tSparcinstruction);
  32. procedure handlepercent;override;
  33. end;
  34. Implementation
  35. uses
  36. { helpers }
  37. cutils,
  38. { global }
  39. globtype,verbose,
  40. systems,
  41. { aasm }
  42. cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
  43. { symtable }
  44. symconst,symsym,
  45. { parser }
  46. scanner,
  47. procinfo,
  48. rabase,rautils,
  49. cgbase,cgobj
  50. ;
  51. procedure TSparcReader.ReadSym(oper : tSparcoperand);
  52. var
  53. tempstr : string;
  54. typesize,l,k : aint;
  55. begin
  56. tempstr:=actasmpattern;
  57. Consume(AS_ID);
  58. { typecasting? }
  59. if (actasmtoken=AS_LPAREN) and
  60. SearchType(tempstr,typesize) then
  61. begin
  62. oper.hastype:=true;
  63. Consume(AS_LPAREN);
  64. BuildOperand(oper);
  65. Consume(AS_RPAREN);
  66. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  67. oper.SetSize(typesize,true);
  68. end
  69. else
  70. if not oper.SetupVar(tempstr,false) then
  71. Message1(sym_e_unknown_id,tempstr);
  72. { record.field ? }
  73. if actasmtoken=AS_DOT then
  74. begin
  75. BuildRecordOffsetSize(tempstr,l,k);
  76. inc(oper.opr.ref.offset,l);
  77. end;
  78. end;
  79. procedure TSparcReader.ReadPercent(oper : tSparcoperand);
  80. begin
  81. { check for ...@ }
  82. if actasmtoken=AS_AT then
  83. begin
  84. if (oper.opr.ref.symbol=nil) and
  85. (oper.opr.ref.offset = 0) then
  86. Message(asmr_e_invalid_reference_syntax);
  87. Consume(AS_AT);
  88. if actasmtoken=AS_ID then
  89. begin
  90. if upper(actasmpattern)='LO' then
  91. oper.opr.ref.refaddr:=addr_lo
  92. else if upper(actasmpattern)='HI' then
  93. oper.opr.ref.refaddr:=addr_hi
  94. else
  95. Message(asmr_e_invalid_reference_syntax);
  96. Consume(AS_ID);
  97. end
  98. else
  99. Message(asmr_e_invalid_reference_syntax);
  100. end;
  101. end;
  102. Procedure TSparcReader.BuildReference(oper : tSparcoperand);
  103. var
  104. l : aint;
  105. regs : byte;
  106. hasimm : boolean;
  107. begin
  108. oper.initref;
  109. regs:=0;
  110. hasimm:=false;
  111. Consume(AS_LBRACKET);
  112. repeat
  113. Case actasmtoken of
  114. AS_INTNUM,
  115. AS_MINUS,
  116. AS_PLUS:
  117. Begin
  118. if hasimm or (regs>1) then
  119. Begin
  120. Message(asmr_e_invalid_reference_syntax);
  121. RecoverConsume(true);
  122. break;
  123. End;
  124. oper.opr.Ref.Offset:=BuildConstExpression(false,true);
  125. hasimm:=true;
  126. End;
  127. AS_REGISTER:
  128. Begin
  129. if regs<2 then
  130. begin
  131. if regs=0 then
  132. oper.opr.ref.base:=actasmregister
  133. else
  134. oper.opr.ref.index:=actasmregister;
  135. inc(regs);
  136. end
  137. else
  138. begin
  139. Message(asmr_e_invalid_reference_syntax);
  140. RecoverConsume(true);
  141. break;
  142. end;
  143. Consume(AS_REGISTER);
  144. end;
  145. AS_ID:
  146. Begin
  147. l:=BuildConstExpression(true,true);
  148. inc(oper.opr.ref.offset,l);
  149. End;
  150. AS_RBRACKET:
  151. begin
  152. if (regs=0) and (not hasimm) then
  153. Message(asmr_e_invalid_reference_syntax);
  154. Consume(AS_RBRACKET);
  155. break;
  156. end;
  157. else
  158. Begin
  159. Message(asmr_e_invalid_reference_syntax);
  160. RecoverConsume(false);
  161. break;
  162. end;
  163. end;
  164. until false;
  165. end;
  166. procedure TSparcReader.handlepercent;
  167. var
  168. len : longint;
  169. begin
  170. len:=1;
  171. actasmpattern[len]:='%';
  172. c:=current_scanner.asmgetchar;
  173. { to be a register there must be a letter and not a number }
  174. while c in ['a'..'z','A'..'Z','0'..'9'] do
  175. Begin
  176. inc(len);
  177. actasmpattern[len]:=c;
  178. c:=current_scanner.asmgetchar;
  179. end;
  180. actasmpattern[0]:=chr(len);
  181. uppervar(actasmpattern);
  182. if is_register(actasmpattern) then
  183. exit;
  184. if (actasmpattern='%HI') then
  185. actasmtoken:=AS_HI
  186. else if (actasmpattern='%LO')then
  187. actasmtoken:=AS_LO
  188. else
  189. Message(asmr_e_invalid_register);
  190. end;
  191. Procedure TSparcReader.BuildOperand(oper : tSparcoperand);
  192. var
  193. expr : string;
  194. typesize,l : aint;
  195. procedure AddLabelOperand(hl:tasmlabel);
  196. begin
  197. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  198. is_calljmp(actopcode) then
  199. begin
  200. oper.opr.typ:=OPR_SYMBOL;
  201. oper.opr.symbol:=hl;
  202. end
  203. else
  204. begin
  205. oper.InitRef;
  206. oper.opr.ref.symbol:=hl;
  207. end;
  208. end;
  209. procedure MaybeRecordOffset;
  210. var
  211. hasdot : boolean;
  212. l,
  213. toffset,
  214. tsize : aint;
  215. begin
  216. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  217. exit;
  218. l:=0;
  219. hasdot:=(actasmtoken=AS_DOT);
  220. if hasdot then
  221. begin
  222. if expr<>'' then
  223. begin
  224. BuildRecordOffsetSize(expr,toffset,tsize);
  225. inc(l,toffset);
  226. oper.SetSize(tsize,true);
  227. end;
  228. end;
  229. if actasmtoken in [AS_PLUS,AS_MINUS] then
  230. inc(l,BuildConstExpression(true,false));
  231. case oper.opr.typ of
  232. OPR_LOCAL :
  233. begin
  234. { don't allow direct access to fields of parameters, because that
  235. will generate buggy code. Allow it only for explicit typecasting }
  236. if hasdot and
  237. (not oper.hastype) and
  238. (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  239. (current_procinfo.procdef.proccalloption<>pocall_register) then
  240. Message(asmr_e_cannot_access_field_directly_for_parameters);
  241. inc(oper.opr.localsymofs,l)
  242. end;
  243. OPR_CONSTANT :
  244. inc(oper.opr.val,l);
  245. OPR_REFERENCE :
  246. inc(oper.opr.ref.offset,l);
  247. else
  248. internalerror(200309221);
  249. end;
  250. end;
  251. var
  252. tempreg : tregister;
  253. tempstr : string;
  254. tempsymtyp : TAsmSymType;
  255. hl : tasmlabel;
  256. gotplus,
  257. negative : boolean;
  258. Begin
  259. expr:='';
  260. gotplus:=true;
  261. negative:=false;
  262. repeat
  263. case actasmtoken of
  264. AS_MINUS :
  265. begin
  266. consume(AS_MINUS);
  267. negative:=true;
  268. gotplus:=true;
  269. end;
  270. AS_PLUS :
  271. begin
  272. consume(AS_PLUS);
  273. negative:=false;
  274. gotplus:=true;
  275. end;
  276. AS_INTNUM,
  277. AS_MOD:
  278. Begin
  279. if not gotplus then
  280. Message(asmr_e_invalid_reference_syntax);
  281. l:=BuildConstExpression(True,False);
  282. if negative then
  283. l:=-l;
  284. { Constant memory offset }
  285. oper.InitRef;
  286. oper.opr.ref.refaddr:=addr_full;
  287. oper.opr.ref.offset:=l;
  288. GotPlus:=(prevasmtoken=AS_PLUS) or
  289. (prevasmtoken=AS_MINUS);
  290. if GotPlus then
  291. negative:=(prevasmtoken=AS_MINUS);
  292. end;
  293. AS_LBRACKET :
  294. begin
  295. { memory reference }
  296. BuildReference(oper);
  297. gotplus:=false;
  298. end;
  299. AS_HI,
  300. AS_LO:
  301. begin
  302. { Low or High part of a constant (or constant
  303. memory location) }
  304. oper.InitRef;
  305. if actasmtoken=AS_LO then
  306. oper.opr.ref.refaddr:=addr_lo
  307. else
  308. oper.opr.ref.refaddr:=addr_hi;
  309. Consume(actasmtoken);
  310. Consume(AS_LPAREN);
  311. BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
  312. if not assigned(oper.opr.ref.symbol) then
  313. oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr)
  314. else
  315. Message(asmr_e_cant_have_multiple_relocatable_symbols);
  316. case oper.opr.typ of
  317. OPR_CONSTANT :
  318. inc(oper.opr.val,l);
  319. OPR_LOCAL :
  320. inc(oper.opr.localsymofs,l);
  321. OPR_REFERENCE :
  322. inc(oper.opr.ref.offset,l);
  323. else
  324. internalerror(200309202);
  325. end;
  326. Consume(AS_RPAREN);
  327. gotplus:=false;
  328. end;
  329. AS_ID: { A constant expression, or a Variable ref. }
  330. Begin
  331. { Local Label ? }
  332. if is_locallabel(actasmpattern) then
  333. begin
  334. CreateLocalLabel(actasmpattern,hl,false);
  335. Consume(AS_ID);
  336. AddLabelOperand(hl);
  337. end
  338. else
  339. { Check for label }
  340. if SearchLabel(actasmpattern,hl,false) then
  341. begin
  342. Consume(AS_ID);
  343. AddLabelOperand(hl);
  344. end
  345. else
  346. { probably a variable or normal expression }
  347. { or a procedure (such as in CALL ID) }
  348. Begin
  349. { is it a constant ? }
  350. if SearchIConstant(actasmpattern,l) then
  351. Begin
  352. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  353. Message(asmr_e_invalid_operand_type);
  354. BuildConstantOperand(oper);
  355. end
  356. else
  357. begin
  358. expr:=actasmpattern;
  359. Consume(AS_ID);
  360. { typecasting? }
  361. if (actasmtoken=AS_LPAREN) and
  362. SearchType(expr,typesize) then
  363. begin
  364. oper.hastype:=true;
  365. Consume(AS_LPAREN);
  366. BuildOperand(oper);
  367. Consume(AS_RPAREN);
  368. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  369. oper.SetSize(typesize,true);
  370. end
  371. else
  372. begin
  373. if oper.SetupVar(expr,false) then
  374. ReadPercent(oper)
  375. else
  376. Begin
  377. { look for special symbols ... }
  378. if expr= '__HIGH' then
  379. begin
  380. consume(AS_LPAREN);
  381. if not oper.setupvar('high'+actasmpattern,false) then
  382. Message1(sym_e_unknown_id,'high'+actasmpattern);
  383. consume(AS_ID);
  384. consume(AS_RPAREN);
  385. end
  386. else
  387. if expr = '__RESULT' then
  388. oper.SetUpResult
  389. else
  390. if expr = '__SELF' then
  391. oper.SetupSelf
  392. else
  393. if expr = '__OLDEBP' then
  394. oper.SetupOldEBP
  395. else
  396. Message1(sym_e_unknown_id,expr);
  397. end;
  398. end;
  399. end;
  400. if actasmtoken=AS_DOT then
  401. MaybeRecordOffset;
  402. { add a constant expression? }
  403. if (actasmtoken=AS_PLUS) then
  404. begin
  405. l:=BuildConstExpression(true,false);
  406. case oper.opr.typ of
  407. OPR_CONSTANT :
  408. inc(oper.opr.val,l);
  409. OPR_LOCAL :
  410. inc(oper.opr.localsymofs,l);
  411. OPR_REFERENCE :
  412. inc(oper.opr.ref.offset,l);
  413. else
  414. internalerror(200309202);
  415. end;
  416. end
  417. end;
  418. gotplus:=false;
  419. end;
  420. AS_REGISTER: { Register, a variable reference or a constant reference }
  421. Begin
  422. { save the type of register used. }
  423. tempreg:=actasmregister;
  424. Consume(AS_REGISTER);
  425. if (oper.opr.typ in [OPR_REGISTER,OPR_REFERENCE]) and gotplus then
  426. begin
  427. oper.initref;
  428. oper.opr.ref.refaddr:=addr_full;
  429. if oper.opr.ref.base<>NR_NO then
  430. oper.opr.ref.base:=tempreg
  431. else
  432. if oper.opr.ref.index<>NR_NO then
  433. oper.opr.ref.index:=tempreg
  434. else
  435. Message(asmr_e_multiple_index);
  436. end
  437. else
  438. begin
  439. if (oper.opr.typ<>OPR_NONE) then
  440. Message(asmr_e_invalid_operand_type);
  441. oper.opr.typ:=OPR_REGISTER;
  442. oper.opr.reg:=tempreg;
  443. end;
  444. gotplus:=false;
  445. end;
  446. AS_END,
  447. AS_SEPARATOR,
  448. AS_COMMA:
  449. break;
  450. else
  451. Begin
  452. Message(asmr_e_syn_operand);
  453. Consume(actasmtoken);
  454. end;
  455. end; { end case }
  456. until false;
  457. end;
  458. {*****************************************************************************
  459. TSparcReader
  460. *****************************************************************************}
  461. procedure TSparcReader.BuildOpCode(instr : tSparcinstruction);
  462. var
  463. operandnum : longint;
  464. Begin
  465. { opcode }
  466. if (actasmtoken<>AS_OPCODE) then
  467. Begin
  468. Message(asmr_e_invalid_or_missing_opcode);
  469. RecoverConsume(true);
  470. exit;
  471. end;
  472. { Fill the instr object with the current state }
  473. with instr do
  474. begin
  475. Opcode:=ActOpcode;
  476. condition:=ActCondition;
  477. end;
  478. { We are reading operands, so opcode will be an AS_ID }
  479. operandnum:=1;
  480. Consume(AS_OPCODE);
  481. { Zero operand opcode ? }
  482. if actasmtoken in [AS_SEPARATOR,AS_END] then
  483. begin
  484. operandnum:=0;
  485. exit;
  486. end;
  487. { delayslot annulled? }
  488. if (actasmtoken=AS_COMMA) then
  489. begin
  490. consume(AS_COMMA);
  491. if actasmpattern='A' then
  492. instr.delayslot_annulled:=true;
  493. { force reading of AS_COMMA instead of AS_ID, otherwise
  494. a label .L0 will first read a AS_DOT instead of AS_ID }
  495. actasmtoken:=AS_COMMA;
  496. consume(AS_COMMA);
  497. end;
  498. { Read the operands }
  499. repeat
  500. case actasmtoken of
  501. AS_COMMA: { Operand delimiter }
  502. Begin
  503. if operandnum>Max_Operands then
  504. Message(asmr_e_too_many_operands)
  505. else
  506. begin
  507. { condition operands doesn't set the operand but write to the
  508. condition field of the instruction
  509. }
  510. if instr.Operands[operandnum].opr.typ<>OPR_NONE then
  511. Inc(operandnum);
  512. end;
  513. Consume(AS_COMMA);
  514. end;
  515. AS_SEPARATOR,
  516. AS_END : { End of asm operands for this opcode }
  517. begin
  518. break;
  519. end;
  520. else
  521. BuildOperand(instr.Operands[operandnum] as tSparcoperand);
  522. end; { end case }
  523. until false;
  524. if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
  525. dec(operandnum);
  526. instr.Ops:=operandnum;
  527. end;
  528. function TSparcReader.is_asmopcode(const s: string):boolean;
  529. var
  530. str2opEntry: tstr2opEntry;
  531. cond:TAsmCond;
  532. Begin
  533. { making s a value parameter would break other assembler readers }
  534. is_asmopcode:=false;
  535. { clear op code }
  536. actopcode:=A_None;
  537. { clear condition }
  538. fillchar(actcondition,sizeof(actcondition),0);
  539. str2opentry:=tstr2opentry(iasmops.search(s));
  540. if assigned(str2opentry) then
  541. begin
  542. actopcode:=str2opentry.op;
  543. actasmtoken:=AS_OPCODE;
  544. is_asmopcode:=true;
  545. end
  546. { not found, check branch instructions }
  547. else if (Upcase(s[1])='B') or
  548. ((Upcase(s[1])='F') and (Upcase(s[2])='B')) then
  549. begin
  550. { we can search here without an extra table which is sorted by string length
  551. because we take the whole remaining string without the leading B }
  552. if (Upcase(s[1])='F') then
  553. actopcode := A_FBxx
  554. else
  555. actopcode := A_Bxx;
  556. for cond:=low(TAsmCond) to high(TAsmCond) do
  557. if (Upper(copy(s,2,length(s)-1))=Upper(Cond2Str[cond])) then
  558. begin
  559. actasmtoken:=AS_OPCODE;
  560. actcondition:=cond;
  561. is_asmopcode:=true;
  562. end;
  563. end;
  564. end;
  565. procedure TSparcReader.ConvertCalljmp(instr : tSparcinstruction);
  566. var
  567. newopr : toprrec;
  568. begin
  569. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  570. with newopr do
  571. begin
  572. typ:=OPR_SYMBOL;
  573. symbol:=instr.Operands[1].opr.ref.symbol;
  574. symofs:=instr.Operands[1].opr.ref.offset;
  575. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  576. (instr.Operands[1].opr.ref.index<>NR_NO) or
  577. (instr.Operands[1].opr.ref.refaddr<>addr_full) then
  578. Message(asmr_e_syn_operand);
  579. instr.Operands[1].opr:=newopr;
  580. end;
  581. end;
  582. procedure TSparcReader.handleopcode;
  583. var
  584. instr : tSparcinstruction;
  585. begin
  586. instr:=TSparcInstruction.Create(TSparcOperand);
  587. BuildOpcode(instr);
  588. with instr do
  589. begin
  590. condition := actcondition;
  591. if is_calljmp(opcode) then
  592. ConvertCalljmp(instr);
  593. ConcatInstruction(curlist);
  594. Free;
  595. end;
  596. end;
  597. {*****************************************************************************
  598. Initialize
  599. *****************************************************************************}
  600. const
  601. asmmode_Sparc_att_info : tasmmodeinfo =
  602. (
  603. id : asmmode_Sparc_gas;
  604. idtxt : 'GAS';
  605. casmreader : TSparcReader;
  606. );
  607. asmmode_Sparc_standard_info : tasmmodeinfo =
  608. (
  609. id : asmmode_standard;
  610. idtxt : 'STANDARD';
  611. casmreader : TSparcReader;
  612. );
  613. initialization
  614. RegisterAsmMode(asmmode_Sparc_att_info);
  615. RegisterAsmMode(asmmode_Sparc_standard_info);
  616. end.